了解F#值限制 [英] Understanding F# value restriction

查看:46
本文介绍了了解F#值限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习F#.我在这里是因为我对价值限制有些了解.

I'm learning F#. I'm here because I had something hard to understand about value restriction.

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

Here are the examples from the book I'm studying with.

let mapFirst = List.map fst

由于我是通过haskell学习FP的,所以我很确定此代码可以正确编译,但事实并非如此.它导致错误 FS0030 (很抱歉,我无法复制粘贴fsi错误消息,因为它是用韩语编写的).相反,我必须提供一个明确的参数,例如:

Since I had learned FP with haskell, I was pretty sure that this code would be well compiled, but it was not the case. It resulted error FS0030 (Sorry that I can't copy-paste fsi error message, since it was written in korean). Instead, I had to provide an explicit argument like:

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

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

But why? I thought that with the above example, compiler can surely infer the type of given value:

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

如果我没有记错,我在haskell eta-conversion 中称这件事,上面两个示例完全相同.(不过,可能不是全部).为什么我应该显式地为函数私有参数,而不会丢失任何信息?

If I remind correctly, I called this thing in haskell eta-conversion, and above two examples are entirely identical. (Maybe not entirely, though). Why should I privide parameters explicitly to the function can be curried without any loss of information?

我了解类似

let empties = Array.create 100 []

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

will not compile and why, but I don't think It has something to do with my question.

※我看了这个问题,但没有帮助.

※ I took a look on this question, but it did not help.

推荐答案

这与可变性有关.

请考虑以下代码段:

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

let t = { x = None }

t 的类型是 T<'a> -即 t 是通用的,它具有通用参数'a ,表示 tx 可以是任何类型-消费者选择什么.

The type of t is T<'a> - that is, t is generic, it has a generic parameter 'a, meaning t.x can be of any type - whatever the consumer chooses.

然后,假设您在程序的一部分中进行了操作:

Then, suppose in one part of the program you do:

t.x <- Some 42

完全合法:访问 t 时,选择'a = int ,然后选择 tx:int选项,因此您可以按里面有42 .

Perfectly legitimate: when accessing t you choose 'a = int and then t.x : int option, so you can push Some 42 into it.

然后,假设您在程序的另一部分中进行了操作:

Then, suppose in another part of your program you do:

t.x <- Some "foo"

哦,是的,现在会发生什么?是 t.x:int选项还是 string选项?如果编译器忠实地编译您的代码,则将导致数据损坏.因此,以防万一,编译器会拒绝.

Oh noes, what happens now? Is t.x : int option or is it string option? If the compiler faithfully compiled your code, it would result in data corruption. So the compiler refuses, just in case.

由于一般而言,编译器无法真正检查类型内部是否存在可变的东西,因此它采用安全路径并拒绝推断为通用的值(表示非函数").

Since in general the compiler can't really check if there is something mutable deep inside your type, it takes the safe route and rejects values (meaning "not functions") that are inferred to be generic.

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

Note that this applies to syntactic values, not logical ones. Even if your value is really a function, but isn't syntactically defined as such (i.e. lacks parameters), the value restriction still applies. As an illustration, consider this:

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

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

let g = f { x = None }

在这里,即使 g 确实是一个函数,该限制的作用也与上面的第一个示例完全相同:每次对 g 的调用都会尝试在相同的通用值 T<'a>

Here, even though g is really a function, the restriction works in exactly the same as with my first example above: every call to g tries to operate on the same generic value T<'a>

在某些较简单的情况下,编译器可以采用快捷方式.因此,例如仅此行不能编译:

In some simpler cases the compiler can take a shortcut though. Thus, for example this line alone doesn't compile:

let f = List.map id

但是这两行可以做到:

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

这是因为第二行允许编译器推断 f:list int->.list int ,因此通用参数消失了,每个人都很高兴.

This is because the second line allows the compiler to infer that f : list int -> list int, so the generic parameter disappears, and everybody is happy.

实际上,此快捷方式涵盖了绝大多数情况.您真正真正违反价值限制的唯一一次尝试是从模块中导出此类通用价值.

In practice it turns out that this shortcut covers the vast majority of cases. The only time you really bump against the value restriction is when you try to export such generic value from the module.

在Haskell中,这种情况不会发生,因为Haskell不接受突变.就这么简单.

In Haskell this whole situation doesn't happen, because Haskell doesn't admit mutation. Simple as that.

但是再说一次,即使Haskell不承认突变,也可以通过 unsafePerformIO 进行.猜猜是什么-在那种情况下,您确实有碰到相同问题的风险.甚至在中提到文档.

But then again, even though Haskell doesn't admit mutation, it kinda sorta does - via unsafePerformIO. And guess what - in that scenario you do risk bumping into the same problem. It's even mentioned in the documentation.

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

Except GHC doesn't refuse to compile it - after all, if you're using unsafePerformIO, you must know what you're doing. Right? :-)

这篇关于了解F#值限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆