教会编码F#免费monad

时间:2017-10-19 13:37:33

标签: f# existential-type free-monad rank-n-types

我试图在F#中表达Free monad的教会编码。 <!-- add all iText 7 Community modules --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>7.0.4</version> <type>pom</type> </dependency> 专门针对特定的仿函数Free

我可以毫无问题地同时编写Effectreturn_ : 'T -> Free<'T>

下面给出了我实施的草图。

bind: ('T -> Free<'U>) -> Free<'T> -> Free<'U>

当我尝试为这种编码编写解释器时,我遇到了一个问题。

给出以下代码:

type Effect<'T>
    = GetStr of (string -> 'T)
    | PutStr of string * 'T


module Effect = 

    let map (f: 'a -> 'b) : Effect<'a> -> Effect<'b> = function
        | GetStr k -> 
            GetStr(f << k)

        | PutStr (s,t) -> 
            PutStr(s, f t)


type Free<'T> =
    abstract Apply : ('T -> 'R) -> (Effect<'R> -> 'R) -> 'R

module Free = 
    let inline runFree (f:Free<'T>) (kp: 'T -> 'R) (kf: Effect<'R> -> 'R) : 'R = 
        f.Apply kp kf

    let return_ (x: 'a) : Free<'a> = 
        { new Free<'a>
            with
                member __.Apply kp _ = 
                    kp x
        }

    let bind (f: 'a -> Free<'b>) (m: Free<'a>) : Free<'b> = 
        { new Free<'b>
            with
                member __.Apply kp kf = 
                    runFree m
                        (fun a -> 
                            runFree (f a) kp kf
                        )
                        kf
        }

我在module Interpret = let interpretEffect = function | GetStr k -> let s = System.Console.ReadLine() (k s , String.length s) | PutStr(s,t) -> do System.Console.WriteLine s (t , 0) let rec interpret (f: Free<string * int>) = Free.runFree f (fun (str,len) -> (str,len)) (fun (a: Effect<Free<string*int>>) -> let (b,n) = interpretEffect a let (c,n') = interpret b (c, n + n') ) 函数中的Free.runFree的第三个参数中出现类型错误:

interpret

我理解为什么会发生这种情况(第一个函数的结果类型确定... (fun (a: Effect<Free<string*int>>) -> ^^^^^^^^^^^^^^^^^^ ------ Expecting a Effect<string * int> but given a Effect<Free<string*int>> )并怀疑可以使用rank-2函数(可以用F#编码,例如http://eiriktsarpalis.github.io/typeshape/#/33)来解决但我不确定如何应用它。

任何指针都会非常感激。

迈克尔

1 个答案:

答案 0 :(得分:1)

你不需要在那里做任何事情,编译器建议的类型实际上是正确的(并且与runFree的类型一致)。

您似乎在想的是斯科特编码(从this Haskell question翻录):

runFree :: Functor f => (a -> r) -> (f (F f a) -> r) -> F f a -> r

其中F f a将是您的Effect - 专门的Free<'a>,而f (F f a)将是Effect<Free<'a>>,这是您尝试使用的内容

而教会编码将是:

runFree :: Functor f => (a -> r) -> (f r -> r) -> F f a -> r

其中f rEffect<'a> - 从而更容易在F#中表达(这就是为什么我假设您首先使用它。

这就是我对interpret所拥有的:

let rec interpret (f: Free<string * int>) = 
    Free.runFree
        f
        (fun (str,len) -> (str,len))
        (fun (a: Effect<_>) -> 
            let (b,n) = interpretEffect a 
            let (c,n') = interpret (Free.pureF b)
            (c, n + n')
        )

其中pureF

let pureF (x: 'a) : Free<'a> = 
    { new Free<'a> with member __.Apply kp _ = kp x }

即。你的return_功能。

我认为定义相应的freeF函数会清除一些事情(比如为什么Effect<'a>是一个仿函数 - 你在所粘贴的代码中的任何地方都没有使用这个事实。)< / p>