Skip to content

Instantly share code, notes, and snippets.

@ramonsnir
Created December 10, 2011 14:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ramonsnir/2d00ac8242229c6d5e39 to your computer and use it in GitHub Desktop.
Save ramonsnir/2d00ac8242229c6d5e39 to your computer and use it in GitHub Desktop.
HoM for F# 2.1
signature {{FUNCTOR =
type 'a t
val map : ('a -> 'b) -> 'a t -> 'b t
}}
module {{ListFunctor : FUNCTOR =
type 'a t = 'a list
let map = List.map
}}
// inline modules are not compiled into actual modules, i.e. they are private to everyone, except functors which use them by argument
module {{inline ArrayFunctor : FUNCTOR =
type 'a t = 'a []
let map = Array.map
}}
module OptionFunctor =
type 'a t = 'a option
let map = Option.map
module {{OptionFunctor : FUNCTOR}}
// the HoM system will assume from now on that there is a module
// named OptionFunctor which matches that signature FUNCTOR.
functor {{ComposeFunctorsFn(A : FUNCTOR, B : FUNCTOR) : FUNCTOR =
type 'a t = 'a A.t B.t
let map f = B.map (A.map f)
}}
module {{ListOptionFunctor = ComposeFunctorsFn(ListFunctor, OptionFunctor)}}
module {{ArrayOptionFunctor = ComposeFunctorsFn(ArrayFunctor, OptionFunctor)}}
signature {{MONAD =
type 'a t
val ``return`` : 'a -> 'a t
val bind : ('a -> 'b t) -> 'a t -> 'b t
}}
module {{ListMonadBase : MONAD =
type 'a t = 'a list
let ``return`` x = [x]
let bind = List.collect
}}
module {{OptionMonadBase : MONAD =
type 'a t = 'a option
let ``return`` = Some
let bind = Option.bind
}}
signature {{MONAD_CE =
inherit MONAD
type CE
val ce : CE
}}
functor {{MonadWithComputationExpressionFn(M : MONAD) : MONAD_CE =
type 'a t = 'a M.t
let ``return`` = M.``return``
let bind = M.bind
type CE internal () =
member __.Return x = ``return`` x
member __.Bind (x, f) = bind f x
let ce = CE()
}}
module {{ListMonad = MonadWithComputationExpressionFn(ListMonadBase)}}
module {{OptionMonad = MonadWithComputationExpressionFn(OptionMonadBase)}}
functor {{MonadToFunctorFn(M : MONAD) : FUNCTOR =
type 'a t = 'a M.t
let map f = M.bind (f >> M.``return``)
}}
module {{ListFunctor2 = MonadToFunctorFn(ListMonad)}} // yes, MONAD_CE is also MONAD!
module {{OptionFunctor2 = MonadToFunctorFn(OptionMonad)}}
let threeToTwelve =
ListMonad.ce {
let! x = [1 .. 10]
let! y = [2]
return x + y
}
(*
The assembly attributes are used when another F# projects imports this project and would like to reuse the signatures/functors.
*)
[<assembly: FSharp.HigherOrderModules.Runtime.Signature("FUNCTOR", " type 'a t\r\n val map : ('a -> 'b) -> 'a t -> 'b t\r\n")>]
do ()
// this dummy module is so the signature will be tc'ed even if it isn't used
module private ``hom test module 6b4ad128 for FUNCTOR`` =
type private 'a t = T of 'a
let private map (_ : ('a -> 'b)) : 'a t -> 'b t = unbox null
module ListFunctor =
type 'a t = 'a list
let map : ('a -> 'b) -> 'a t -> 'b t = List.map
[<assembly: FSharp.HigherOrderModules.Runtime.InlineModule("ArrayFunctor", "inline ArrayFunctor : FUNCTOR =\r\n type 'a t = 'a []\r\n let map = Array.map\r\n")>]
do()
module private ``hom test module 55d2daec for ArrayFunctor`` =
type private 'a t = 'a []
let private map : ('a -> 'b) -> 'a t -> 'b t = Array.map
module OptionFunctor =
type 'a t = 'a option
let map = Option.map
[<assembly: FSharp.HigherOrderModules.Runtime.ModuleSignature("OptionFunctor", "FUNCTOR")>]
do ()
[<assembly: FSharp.HigherOrderModules.Runtime.Functor("ComposeFunctorsFn", "(A : FUNCTOR, B : FUNCTOR) : FUNCTOR =\r\n type 'a t = 'a A.t B.t\r\n let map f = B.map (A.map f)\r\n")>]
do ()
// this dummy module is so the functor will be tc'ed even if it isn't used
module private ``hom test module 8e37694b for ComposeFunctorsFn`` =
module private A =
type 'a t = T of 'a
let map (_ : ('a -> 'b)) : 'a t -> 'b t = unbox null
module private B =
type 'a t = T of 'a
let map (_ : ('a -> 'b)) : 'a t -> 'b t = unbox null
type private 'a t = 'a A.t B.t
let private map (f : 'a -> 'b) : 'a t -> 'b t = B.map (A.map f)
module ListOptionFunctor =
module A = ListFunctor
module B = OptionFunctor
type 'a t = 'a A.t B.t
let map (f : 'a -> 'b) : 'a t -> 'b t = B.map (A.map f)
module ArrayOptionFunctor =
module A =
type 'a t = 'a []
let map = Array.map
module B = OptionFunctor
type 'a t = 'a A.t B.t
let map (f : 'a -> 'b) : 'a t -> 'b t = B.map (A.map f)
[<assembly: FSharp.HigherOrderModules.Runtime.Signature("MONAD", " type 'a t\r\n val ``return`` : 'a -> 'a t\r\n val bind : ('a -> 'b t) -> 'a t -> 'b t\r\n")>]
do ()
module private ``hom test module 6b4fe428 for MONAD`` =
type private 'a t = T of 'a
let private ``return`` (_ : 'a) : 'a t = unbox null
let private bind (_ : ('a -> 'b t)) : 'a t -> 'b t = unbox null
module ListMonadBase =
type 'a t = 'a list
let ``return`` (x : 'a) : 'a t = [x]
let bind : ('a -> 'b t) -> 'a t -> 'b t = List.collect
module OptionMonadBase =
type 'a t = 'a option
let ``return`` : 'a -> 'a t = Some
let bind : ('a -> 'b t) -> 'a t -> 'b t = Option.bind
[<assembly: FSharp.HigherOrderModules.Runtime.Signature("MONAD_CE", " inherit MONAD\r\n type CE\r\n val ce : CE\r\n")>]
do ()
module private ``hom test module 75c6e428 for MONAD_CE`` =
type private 'a t = T of 'a
let private ``return`` (_ : 'a) : 'a t = unbox null
let private bind (_ : ('a -> 'b t)) : 'a t -> 'b t = unbox null
type private CE = CE of unit
let private ce : CE = CE()
[<assembly: FSharp.HigherOrderModules.Runtime.Functor("MonadWithComputationExpressionFn", "(M : MONAD) : MONAD_CE =\r\n type 'a t = 'a M.t\r\n let ``return`` = M.``return``\r\n let bind = M.bind\r\n type CE internal () =\r\n member __.Return x = ``return`` x\r\n member __.Bind (x, f) = bind f x\r\n let ce = CE()\r\n")>]
do ()
// this dummy module is so the functor will be tc'ed even if it isn't used
module private ``hom test module 45a458cb for MonadWithComputationExpressionFn`` =
module private M =
type 'a t = T of 'a
let ``return`` (_ : 'a) : 'a t = unbox null
let bind (x0 : ('a -> 'b t)) : 'a t -> 'b t = unbox null
type private 'a t = 'a M.t
let private ``return`` (x0 : 'a) : 'a t = M.``return`` x0
let private bind (x0 : ('a -> 'b t)) : 'a t -> 'b t = M.bind x0
type private CE internal () =
member __.Return x = ``return`` x
member __.Bind (x, f) = bind f x
let private ce : CE = CE()
module ListMonad =
module M = ListMonadBase
type 'a t = 'a M.t
let ``return`` : 'a -> 'a t = M.``return``
let bind : ('a -> 'b t) -> 'a t -> 'b t = M.bind
type CE internal () =
member __.Return x = ``return`` x
member __.Bind (x, f) = bind f x
let ce : CE = CE()
module OptionMonad =
module M = OptionMonadBase
type 'a t = 'a M.t
let ``return`` : 'a -> 'a t = M.``return``
let bind : ('a -> 'b t) -> 'a t -> 'b t = M.bind
type CE internal () =
member __.Return x = ``return`` x
member __.Bind (x, f) = bind f x
let ce : CE = CE()
[<assembly: FSharp.HigherOrderModules.Runtime.Functor("MonadToFunctorFn", "(M : MONAD) : FUNCTOR =\r\n type 'a t = 'a M.t\r\n let map f = M.bind (f >> M.``return``)\r\n")>]
do ()
module private ``hom test module 456b6a2d for MonadToFunctorFn`` =
module private M =
type 'a t = T of 'a
let ``return`` (_ : 'a) : 'a t = unbox null
let bind (_ : ('a -> 'b t)) : 'a t -> 'b t = unbox null
type private 'a t = 'a M.t
let private map (f : 'a -> 'b) : 'a t -> 'b t = M.bind (f >> M.``return``)
module ListFunctor2 =
module M = ListMonad
type 'a t = 'a M.t
let map (f : 'a -> 'b) : 'a t -> 'b t = M.bind (f >> M.``return``)
module OptionFunctor2 =
module M = OptionMonad
type 'a t = 'a M.t
let map (f : 'a -> 'b) : 'a t -> 'b t = M.bind (f >> M.``return``)
let threeToTwelve =
ListMonad.ce {
let! x = [1 .. 10]
let! y = [2]
return x + y
}
@panesofglass
Copy link

This is really interesting! Have you looked to see if any of this could be used within the type provider infrastructure now that it has evolved some?

@ramonsnir
Copy link
Author

In theory it could. One solution is to use type providers as preprocessors (i.e. make an .fshm file with code as in the first file here, then use type providers to read that file and supply the modules).

@panesofglass
Copy link

I noticed that quotations aren't supported. I wonder if there's still time to add support? Care to suggest some of your ideas on this thread?

@ramonsnir
Copy link
Author

Late late response... Not so active on GitHub lately. Why aren't quotations supported? I know Type Providers dislike quotations (which is a terrible design flaw), but macros have no such problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment