我试图在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
。
我可以毫无问题地同时编写Effect
和return_ : '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)来解决但我不确定如何应用它。
任何指针都会非常感激。
迈克尔
答案 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 r
为Effect<'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>