我正在与几行可怜的代码作斗争,但我无法理解这个问题——无论出于什么原因,我都无法理解F#类型系统的这一方面的原理,到目前为止,我所有的阅读都没有奏效。
有人能向我指出我在这里犯的相当愚蠢的学生错误吗?我知道我在做一个,我就是看不见!我正试图从这片痛苦的初学者土地上爬出来,所以我的目标是探索为什么这不起作用的全部原理——任何帮助都将不胜感激!
这是一个简单的练习——实际上只是一个练习,并不需要monad来执行,但我真的希望这些东西能在我的下一个项目中发挥作用。
let stringToInt str = Int32.TryParse(str)
type wk() =
member this.Bind(f , str) = f str
member this.Return(f ) = f
let strInt = new wk()
let test a = strInt{let! b = strInt.Bind a stringToInt
return b}
let x = test "10"
printfn "%s" x
我得到以下信息:
Program.fs(117,14): error FS0001: This expression was expected to have type
(string -> bool * int) -> ('a -> 'a) -> 'b
but here has type string
更新:基于下面的帮助,我现在有这个工作:
open System
open System.Threading
let stringToInt str = snd <| Int32.TryParse(str)
type wk() =
member this.Bind(funct, str) = funct str
member this.Return(str) = str
let strInt = new wk()
//Jack P syntax!
let test2 str funct = strInt{
let! b = funct str
return b
}
let go2 = test2 ("10", stringToInt) |> printfn "%A"
尽管工作在概念上可能还不存在——但要把价值打印出来还没有发生。我会继续努力——我已经读了很多书,这就是我得到这个练习的地方,但我想,我得到这个概念的唯一方法就是继续与它斗争。
我在博客上以一种更简单的形式取得了成功:http://richardgriffiths.azurewebsites.net/?p=2332所以我只需要打破我在类型系统中遇到的语法/概念障碍。
F#中计算表达式的全部意义在于,您不必在构建器实例上显式调用Bind
、Return
等方法(本例中为strInt
)。这就是let
和let!
之间的区别——在计算表达式中,let!
绑定被编译,因此它们调用构建器实例的Bind
方法。所以你应该这样写你的代码:
let test a =
strInt {
let! b = stringToInt a
return b
}
然而,上面的代码仍然不能工作,因为Bind
和Return
方法没有正确定义(它们不是一元的)。我赞同Patryk的建议(在他的评论中)——在你开始写自己的单子之前,你应该花一些时间练习简单、常见的单子(例如option
)。使用F#计算表达式很容易,但定义自己的计算表达式是一个中级/高级主题。
您已经定义了Bind
来接受元组参数(这对于计算生成器来说是正确的),但您正在以当前形式传递参数(strInt.Bind a stringToInt
而不是strInt.Bind(a, stringToInt)
)。