Дополнительные параметры и типы опций с использованием 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 не делает.

Спасибо за разъяснение

Ответ 1

Я должен пересмотреть правильный ответ. На основании этого вопроса (и ответа):

Распространение необязательных аргументов

это означает, что правильный ответ таков:

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)

Это аккуратная функция и кредиты для ответа перейдите на desco!

Ответ 2

  • 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
    
  • 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')