recursion - 处理“统一时生成的类型将是无限的”
问题描述
let rec bind x f = f x |> bind
bind "Hello World" (fun x -> x.toUpper()) printf "%s"
上面的代码片段会导致此错误“统一时生成的类型将是无限的”。
编译器的建议:“基于此程序点之前的信息查找不确定类型的对象。在此程序点之前可能需要类型注释来约束对象的类型。这可能允许解析查找。”
正如编译器所说,添加类型注释将解决此问题。您将如何编写满足编译器的类型注释?
这可能会有所帮助。由于 Javascript 更宽容且不会抱怨,因此您可以查看将同一段代码翻译成 JS 的工作示例。
const bind = x => f => bind(f(x))
bind("Hello World")
(x => x.toUpperCase())
(console.log)
解决方案
问题是bind
您尝试定义的函数没有可以在标准 F# 中表达的类型。你想要一个类型看起来像这样的函数:
'A -> ('A -> 'B) -> ('B -> 'C) -> ('C -> 'D) -> ('D -> 'E) -> ....
换句话说,该bind
函数应该接受输入和应用于它们的一系列函数,但您并没有限制该序列的长度。标准的 F# 类型系统没有表达这一点的方式,因此人们通常使用其他模式。在您的情况下,它将是|>
操作员。与您的 相比bind
,您必须|>
重复编写,但这通常没问题:
"Hello World"
|> (fun x -> x.ToUpper())
|> printf "%s"
也就是说,我认为您的示例选择不当,我只想写:
printf "%s" ("Hello world".ToUpper())
最后,bind
由于 F# 静态成员约束,可以使用重载来定义类似函数的东西。这些方面的东西,但是|>
是做你的例子说明的事情的惯用和干净的解决方案。
推荐阅读
- python - 当样本长度与总体相同时,Python random.sample 给出“样本大于总体或为负”
- php - 在 Woocommerce 结帐国家/地区选择字段中使美国成为第一
- javascript - 如何使用 Node.js 创建具有多个服务器但只有一个 URL 的游戏?
- django - 如何使用 PrimaryKeyRelatedField 在 ModelSerializer 中将所有者重命名为 owner_id?
- c - 可以表示为浮点数的最大奇数
- python - 避免重复循环,每次到达末尾时都会重复一条指令
- c# - 使用 Guid 反序列化类不会解析回 guid 值
- java - 打印数组中最大的 2 个数字
- python-3.x - 浮点除法后存储零
- java - 将频道向上/向下按钮与 Android TV 应用程序关联