generics - Getting or implementing String.Zero and bool.Zero generically for use with monoids -
i trying refactor existing code into more monodic approach. existing code contains interfaces ixinterface
, numerics int
, bool
. numerics have zero
default, interfaces have property gettor, bool
, string
not. 1 way out wrap bool , string in interface, cumbersome.
i figured if f# language manages extend types numerics, perhaps can strings , bools particular situation.
module myzero = let inline get_zero () : ^a = ((^a) : (static member get_zero : unit -> ^a)()) type system.string static member get_zero() = system.string.empty type xr<'t when 't : (static member get_zero : unit -> 't)> = | expression of (someobj -> 't) | action of (int -> 't) | value of 't | empty member inline this.execute(x: someobj) : 't = match | value(v) -> v | expression(ex) -> ex x | action(a) -> x.getlocation | empty -> get_zero() static member map f x= match x | xr.empty -> xr.empty | xr.value v -> xr.value <| f v | xr.action p -> xr.action <| fun v -> f (p v) | xr.expression e -> xr.expression <| fun x -> f (e x) // etc
the above compiles fine, long don't try use strings or bools:
type wihtbool = xr<int> // succeeds type wihtbool = xr<ixinterface> // succeeds type wihtbool = xr<bool> // fails type withstring = xr<string> // fails
the error clear , correct (i have extension method, not recognized obvious reasons), don't know non-intrusive way rid of it:
fails "the type bool not support operator 'get_zero'
fails "the type string not support operator 'get_zero'
f# manages extend numeric types using static optimizations feature disabled outside f# core library.
afaik way similar mechanism using overloads , static member constraints.
indeed trying it's implemented in f#+
#nowarn "3186" #r @"fscontrol.core.dll" #r @"fsharpplus.dll" open fsharpplus let x:string = mempty() // val x : string = "" type boo = boo static member mempty() = boo let y:boo = mempty() // val y : boo = boo
it works on same principle f# math operators static constraint can satisfied type of argument.
here's part of source code makes magic.
currently instance bool
missing, can add issue suggesting or pull request, one-liner (or two).
anyway if want capture functionality try quick-standalone code:
type mempty = static member ($) (_:mempty, _:string) = "" static member ($) (_:mempty, _:bool) = false let inline mempty() :'t = unchecked.defaultof<mempty> $ unchecked.defaultof<'t> let x:string = mempty() // val x : string = "" let y:bool = mempty() // val y : bool = false type boo = boo static member ($) (_:mempty, _:boo) = boo let z:boo = mempty() // val z : boo = boo
you can rename mempty
get_zero
think get_zero
not best name monoid, remember number 1 under multiplication monoid , get_zero
used in f# core libraries generic numbers.
but if going in direction advise consider library since there many issues may find when scaling code resolved there, free other monoid related functions, mconcat
, mfold
, nicer signatures on types.
Comments
Post a Comment