F#无法理解我的多个参数值所具有的定界。为什么?

时间:2014-05-21 16:48:39

标签: .net f#

我实际上遇到了F#编译器可能存在的奇怪问题。以下代码给出了一个错误,我无法理解原因:

    yield Animal(
        AnimalType(animal.AnimalType.Value),
error-->if Option.isSome animal.AnimalSubType then Some(AnimalSubType(animal.AnimalSubType.Value)) else None,
        AnimalSpecificSubType(animal.AnimalSpecificSubType.Value)
        )

编译器抱怨Animal应该接受3个参数但实际上只占用2.我猜它没有意识到if参数在行尾(在逗号中)结束。我可以通过在违规行周围添加()来运行代码:

    yield Animal(
        AnimalType(animal.AnimalType.Value),
--> OK  (if Option.isSome animal.AnimalSubType then Some(AnimalSubType(animal.AnimalSubType.Value)) else None),
        AnimalSpecificSubType(animal.AnimalSpecificSubType.Value)
        )

但我想了解这个问题。为什么这会解决问题,例如,这不是?

    yield Animal(
        AnimalType(amimal.AnimalType.Value),
error-->if (Option.isSome animal.AnimalSubType) then (Some(AnimalSubType(animal.AnimalSubType.Value))) else (None),
        AnimalSpecificSubType(animal.AnimalSpecificSubType.Value)
        )

我没有抬头看过F#的语法,但我猜每次F#看到一个if句子时,它会期望else条款,可能会跟着通过else条款。我猜,只要我对else条款小心,一切都会好的。

这里有什么问题?

2 个答案:

答案 0 :(得分:4)

编译器将错误行末尾的逗号解释为else分支返回的元组的一部分,即

yield Animal(
    a,
    if c then Some(b) else None,
    d 
    )

被解析为:

yield Animal(
    a,
    if c then Some(b) else ((None, ...? )
    d 
    )

这就是为什么你的第一个修复工作而不是第二个,因为在第二个修复中添加括号只包含幻像元组的第一个元素,而不是元组本身,即:

yield Animal(
    a,
    if c then Some(b) else (None),
    d 
    )

被解析为:

yield Animal(
    a,
    if c then Some(b) else ((None), ...? )
    d 
    )

答案 1 :(得分:3)

问题与如何在F#中创建元组有关:

> let test (a,b,c) = "Test"
> test(1, if true then Some 1 else None,1);;

  test(1, if true then Some 1 else None,1);;
  -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error FS0001: Type mismatch. Expecting a
    'a * 'b * 'c    
but given a
    'a * 'b    
The tuples have differing lengths of 3 and 2

这清楚地表明编译器认为test正在采用两个参数,但编译器认为这两个参数是什么?由于这种类型的函数实际上只是将单个参数作为元组的函数,我们可以解释这行代码:

> 1, if true then Some 1 else None,1;;

  1, if true then Some 1 else None,1;;
  ----------------------------^^^^^^

stdin(19,29): error FS0001: This expression was expected to have type
    int option    
but here has type
    'a * 'b

因此,您可以看到编译器将None,1视为else表达式的if中的表达式,这就是编译器期望int option的原因。为了防止这种情况,您需要向编译器指示if表达式的起点和终点。实现这一目标的最简单方法是简单地将括号括在它周围:

> 1,(if true then Some 1 else None),1;;
val it : int * int option * int = (1, Some 1, 1)

现在我们得到了预期的元组。