为什么此无点F#函数的行为与非无点版本不同? [英] Why does this point-free F# function behave differently from the non-point-free version?

查看:169
本文介绍了为什么此无点F#函数的行为与非无点版本不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下F#:-

type TestClass() =
    let getValFromMap m k = Map.find k m

    let addToMap map k i = map |> Map.add k i

    let mutable someMap : Map<string,int> = Map.empty

    let getValFromMapPartial key = getValFromMap someMap key
    let getValFromMapPartialAndTacit = getValFromMap someMap

    member this.AddThenGet() =
        someMap <- addToMap someMap "A" 10

        let value = getValFromMapPartial "A"
        printfn "Value from partial = %i" value   // prints out

        let value = getValFromMapPartialAndTacit "A"  // throws
        printfn "Value from partial and tacit = %i" value

[<EntryPoint>]
let main argv = 
    let test = TestClass()
    test.AddThenGet()
    0

在我看来,功能getValFromMapPartialgetValFromMapPartialAndTacit是相同的. F#表示它们具有完全相同的类型:(string -> int).但是它们的行为截然不同,并且它们的编译也截然不同.使用dotPeek进行反编译,我看到getValFromMapPartial是一种方法,而getValFromMapPartialAndTacit是在ctor中初始化的字段.

Functions getValFromMapPartial and getValFromMapPartialAndTacit are, to my mind, identical. F# says they have the exact same type: (string -> int). And yet they behave very differently, and they are compiled very differently. Decompiling using dotPeek, I see that getValFromMapPartial is a method, whereas getValFromMapPartialAndTacit is a field that is initialized in the ctor.

F#也不会抱怨getValFromMapPartialAndTacit.但是,在上面的示例中调用此函数失败了,可能是因为尽管它具有可变性,但它包装了someMap的初始空白版本.

F# does not complain about getValFromMapPartialAndTacit, even on the highest warning level (both in VS 2012 and 2013). And yet calling this function in my sample above fails, presumably because it has wrapped the initial, empty version of the someMap, despite its mutability.

这两个功能为什么有区别? F#是否应该警告默认/无点版本可能会失败?

Why is there a difference between these two functions? Should there be a warning from F# that the tacit / point-free version might fail?

推荐答案

F#编译器区分具有参数的函数 values 的let绑定.没有参数.

The F# compiler distinguishes between let-bindings of functions, which have parameters, and values, which do not have parameters.

  • 值定义:像let a = ...这样的绑定是值定义.在对代码下方的任何内容进行评估之前,都会急切地对其主体进行所在位置"评估.

  • Value definition: A binding like let a = ... is a value definition. Its body is evaluated eagerly, "where it is", before the evaluation of anything further down the code.

函数定义:let f x = ...这样的绑定是一种语法函数定义,在调用该函数时对其内容进行评估.

Function definition: A binding like let f x = ... is a syntactic function definition, the contents of which are evaluated when the function is called.

由于someMap是指可变变量,因此在函数定义中使用此变量意味着在调用函数时从变量中读取.但是,getValFromMapPartialAndTacit中的用法在声明时读取值 .

Since someMap refers to a mutable variable, using this variable inside a function definition means reading from the variable when the function is called. However, the usage in getValFromMapPartialAndTacit reads the value at the moment of declaration.

此行为不会阻止值成为函数.您也可以编写let f = fun x -> ...来声明一个函数,而...将再次成为函数定义的一部分.但是,如果要在=fun之间添加定义,则将在f定义时对它们进行评估,而不是在调用它时进行评估.

This behavior does not stop a value from being a function. You could just as well write let f = fun x -> ... to declare a function, and ... would again be part of a function definition. However, if you were to add definitions in between the = and fun, they would be evaluated at the point of the definition of f, not when it is called.

在问题的注释中,someMap是可变的参考单元,也会出现相同的问题.这是同样的问题.该功能,由安德鲁(Andrew)重写,用于可变的参考单元格:

In the question's comments, the same problem occurs with someMap being a mutable reference cell. This is the same problem. The function, as rewritten by Andrew for a mutable reference cell:

let getValFromMapPartialAndTacit = getValFromMap !someMap

此处,在绑定值时(而不是在调用函数时)应用取消引用运算符(!).它等效于:

Here, the dereference operator (!) is applied when the value is bound, not when the function is called. it is equivalent to:

let mapRightNow = !someMap
let getValFromMapPartialAndTacit = getValFromMap mapRightNow

这篇关于为什么此无点F#函数的行为与非无点版本不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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