gpt4 book ai didi

f# - 了解 F# 值限制

转载 作者:行者123 更新时间:2023-12-05 02:08:05 25 4
gpt4 key购买 nike

我正在学习 F#。我来这里是因为我对值限制有一些难以理解的东西。

这是我正在学习的书中的示例。

let mapFirst = List.map fst

自从我用 haskell 学习了 FP,我很确定这段代码会被很好地编译,但事实并非如此。导致错误 FS0030(抱歉,我无法复制粘贴 fsi 错误消息,因为它是用韩语编写的)。相反,我必须提供一个明确的论点,例如:

let mapFirst inp = List.map fst inp   // or inp |> List.map fst

但是为什么?我认为通过上面的示例,编译器肯定可以推断出给定值的类型:

val mapFirst : ('a * 'b) list -> 'a list

如果我没记错的话,我在haskell中调用了这个东西eta-conversion,上面两个例子是完全一样的。 (不过,也许不是完全)。为什么我应该显式地提供参数以便可以在不丢失任何信息的情况下对函数进行柯里化(Currying)?

我明白了

let empties = Array.create 100 []

不会编译,为什么,但我认为这与我的问题无关。

※ 我在 this question 上看了看,但没有帮助。

最佳答案

这与可变性有关。

考虑这个片段:

type T<'a> = { mutable x : 'a option }

let t = { x = None }

t 的类型是T<'a> - 即 t是通用的,它有一个通用参数 'a , 意思是 t.x可以是任何类型 - 无论消费者选择什么。

然后,假设您在程序的一部分中执行以下操作:

t.x <- Some 42

完全合法:当访问 t 时你选'a = int然后 t.x : int option , 所以你可以推 Some 42进入其中。

然后,假设您在程序的另一部分执行:

t.x <- Some "foo"

哦不,现在发生了什么?是t.x : int option或者是string option ?如果编译器忠实地编译您的代码,则会导致数据损坏。所以编译器拒绝,以防万一。

由于一般情况下编译器无法真正检查您的类型内部是否存在可变内容,因此它采用安全路线并拒绝被推断为通用的值(意思是“非函数”)。


请注意,这适用于语法 值,而不是逻辑 值。即使您的值确实是一个函数,但在语法上没有这样定义(即缺少参数),值限制仍然适用。作为示例,请考虑以下内容:

type T<'a> = { mutable x : 'a option }

let f t x =
t.x <- Some x

let g = f { x = None }

在这里,即使g确实是一个函数,限制的工作方式与我上面的第一个示例完全相同:每次调用 g尝试对相同的通用值进行操作 T<'a>


在一些更简单的情况下,编译器可以采用捷径。因此,例如,仅此行无法编译:

let f = List.map id

但是这两行:

let f = List.map id
let x = f [1;2;3]

这是因为第二行允许编译器推断出 f : list int -> list int ,所以泛型参数消失了,大家都很高兴。

实践证明,这条捷径涵盖了绝大多数情况。您唯一一次真正遇到值限制是在您尝试从模块中导出此类通用值时。


在 Haskell 中,这种情况不会发生,因为 Haskell 不承认突变。就这么简单。

但话又说回来,即使 Haskell 不承认突变,它也有点承认 - 来自 unsafePerformIO .你猜怎么着——在那种情况下你确实有遇到同样问题的风险。甚至是mentioned in the documentation .

除了 GHC 不会拒绝编译它 - 毕竟,如果你使用 unsafePerformIO ,你必须知道你在做什么。正确的? :-)

关于f# - 了解 F# 值限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61243289/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com