问题 使用F#的可选参数和选项类型


请考虑以下代码:

type Test () =
  member o.fn1 (?bo) = 1
  member o.fn2 (?bo) = o.fn1 bo

  member o.fn3 (?bo) = 1 + bo.Value
  member o.fn4 (?bo) = o.fn3 bo

fn1 和 fn2 工作得很好, fn4 产生以下错误:

init.fsx(6,30):错误FS0001:这个表达式应该是int类型,但是这里有类型'a option

MSDN 状态:

可选参数被解释为F#选项类型,因此您可以通过使用具有Some和None的匹配表达式以查询选项类型的常规方式查询它们。

对我来说,可选参数不会被解释为F#选项类型,否则代码将被编译。此外,当我将鼠标悬停在上面时,我不明白为什么 ?bo 在 fn3 工具提示说 val bo: int option 但是从外面只期待 int。我期望一个接受任何东西的行为,int,Some int和None。作为最后一点,我不明白为什么 fn2 工作,但 fn4 才不是。

谢谢你的澄清


7983
2018-06-15 06:29


起源



答案:


我必须重新考虑正确的答案。基于这个问题(和答案):

传播可选参数

接缝正确的答案如下:

type Test () =
  member o.fn1 (?bo) = 1
  member o.fn2 (?bo) = o.fn1 bo

  member o.fn3 (?bo) = 1 + bo.Value
  member o.fn4 (?bo) = o.fn3 (?bo = bo)

它是一个很好的功能和答案的信用 德斯科


7
2017-08-18 05:15





  1. fn2 因为 fn1 不使用其参数,因此它是通用的 'b option

    type Test () =
       member o.fn1 (?bo1) = 1  --> bo1: 'b option, here 'b = 'a option
       member o.fn2 (?bo) = o.fn1 bo  -->bo: 'a option
    
  2. fn4 抱怨传递的参数 fn3 应该是一个int,但不是 int option 因为当你指定参数时,你当然需要传递一个特定的参数。但您可以选择省略参数。的定义/类型签名 fn3 不知道你是否有指定 bo 或不,所以它是一个 int option。请注意,您可能有以下用法:

    type Test () =
       member o.fn1 (?bo) = 1
       member o.fn2 (?bo) = o.fn1 bo
    
       member o.fn3 (?bo) = 
       match bo with
         | Some v -> 1 + bo.Value
         | None -> 1
    
       member o.fn4 (?bo) = o.fn3()
    

你没有指定参数的地方 fn3,但是当你指定它时,它是具体的 int不是 int option

想想有三个参数的绘图功能:

let plot(?x,?y,?color)

因为参数是可选的,您可以使用以下用法:

plot(data)
plot(y=data)
plot(x=data, color='r')

但不是:

plot(Some data)
plot(y=Some data)
plot(x=Some data, color=Some 'r')

4
2018-06-15 06:41



我收到你的评论,但我仍然不喜欢它的做法。我更希望能够发送 nothing, value, Some value and None。当我想将可选参数从一个成员重新发送到另一个成员时,我必须在第一个成员中对它进行模式匹配,并使用和不使用参数调用第二个成员,或者我必须使用选项类型定义另一个成员并将所有成员重新发送到此成员。 - Oldrich Svec
可选参数是对库用户友好的语法,但不是库编写者。你站在图书馆作家的角度来判断这个功能。接口越动态,底层实现的检查就越多。 - Yin Zhu


答案:


我必须重新考虑正确的答案。基于这个问题(和答案):

传播可选参数

接缝正确的答案如下:

type Test () =
  member o.fn1 (?bo) = 1
  member o.fn2 (?bo) = o.fn1 bo

  member o.fn3 (?bo) = 1 + bo.Value
  member o.fn4 (?bo) = o.fn3 (?bo = bo)

它是一个很好的功能和答案的信用 德斯科


7
2017-08-18 05:15





  1. fn2 因为 fn1 不使用其参数,因此它是通用的 'b option

    type Test () =
       member o.fn1 (?bo1) = 1  --> bo1: 'b option, here 'b = 'a option
       member o.fn2 (?bo) = o.fn1 bo  -->bo: 'a option
    
  2. fn4 抱怨传递的参数 fn3 应该是一个int,但不是 int option 因为当你指定参数时,你当然需要传递一个特定的参数。但您可以选择省略参数。的定义/类型签名 fn3 不知道你是否有指定 bo 或不,所以它是一个 int option。请注意,您可能有以下用法:

    type Test () =
       member o.fn1 (?bo) = 1
       member o.fn2 (?bo) = o.fn1 bo
    
       member o.fn3 (?bo) = 
       match bo with
         | Some v -> 1 + bo.Value
         | None -> 1
    
       member o.fn4 (?bo) = o.fn3()
    

你没有指定参数的地方 fn3,但是当你指定它时,它是具体的 int不是 int option

想想有三个参数的绘图功能:

let plot(?x,?y,?color)

因为参数是可选的,您可以使用以下用法:

plot(data)
plot(y=data)
plot(x=data, color='r')

但不是:

plot(Some data)
plot(y=Some data)
plot(x=Some data, color=Some 'r')

4
2018-06-15 06:41



我收到你的评论,但我仍然不喜欢它的做法。我更希望能够发送 nothing, value, Some value and None。当我想将可选参数从一个成员重新发送到另一个成员时,我必须在第一个成员中对它进行模式匹配,并使用和不使用参数调用第二个成员,或者我必须使用选项类型定义另一个成员并将所有成员重新发送到此成员。 - Oldrich Svec
可选参数是对库用户友好的语法,但不是库编写者。你站在图书馆作家的角度来判断这个功能。接口越动态,底层实现的检查就越多。 - Yin Zhu