开发者

Optional parameters and option types using F#

Consider the fo开发者_StackOverflow中文版llowing code:

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

While fn1 and fn2 work just fine, fn4 produces the following error:

init.fsx(6,30): error FS0001: This expression was expected to have type int but here has type 'a option

MSDN states:

Optional parameters are interpreted as the F# option type, so you can query them in the regular way that option types are queried, by using a match expression with Some and None.

To me, optional parameters are not interpreted as the F# option type otherwise the code would compile. Moreover I do not understand why, when I hover over ?bo in fn3 the tooltip says val bo: int option but from outside expects only int. I would expect a behavior of accepting nothing, int, Some int and None. And as the last note, I do not understand why fn2 works but fn4 does not.

Thanks for clarification


I have to reconsider the correct answer. Based on this question (and answer):

Propagating optional arguments

it seams that the correct answer is the following:

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)

It is a neat feature and credits for the answer go to desco!


  1. fn2 works because fn1 does not use its parameter, which is thus generic '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 complains that the parameter passed to fn3 should be an int, but not int option because when you specify the parameter, you of course need to pass in a specific one. But you have the option to omit the parameter. The definition/type signature of fn3 does not know whether you have specify bo or not, so it is a int option. Notice that you may have the following usage:

    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()
    

where you don't specify the parameter for fn3, but when you specify it, it is a concrete int, not int option.

Think about a plotting function with three parameters:

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

because the parameters are optional, you can have the following usage:

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

But not:

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


F# does not require matching to pass optional arguments. Using the plot-example:

type Plotter() =
    static member Plot(?x,?y,?color) = 
        printfn $"{x}, {y}, {color}" // Do something "plottish" here

type PlotUser() =
    static member MyPlotUser(?x, ?y, ?color) =
        Plotter.Plot(?x = x, ?y = y, ?color = color)

/// Perform calls
PlotUser.MyPlotUser(10) // => Some(10), , 
PlotUser.MyPlotUser(10, color = "Green") // => Some(10), , Some(Green)

The above lets you call plot with your own optional arguments. /JEE, Sharp#Soft

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜