2016-01-20 3 views
3

Я все еще смущен тем, как читать сигнатуры функций.Как интерпретировать подпись функции

Option.map подпись следующее:

/// map f inp evaluates to match inp with None -> None | Some x -> Some (f x). 
/// mapping: A function to apply to the option value. 
/// option: The input option. 
val map : mapping:('T -> 'U) -> option:'T option -> 'U option 

Однако, я не имею ни малейшего понятия, что означает, что подпись.

Я прочитал ее в следующем виде:

Там есть функция, называемая карты, которая принимает функцию в качестве входных данных, которые мы будем называть «отображение» и дадут результат, который также функцию, которую мы назовем «опция».

Отображение параметров:

mapping:('T -> 'U) 

Функция, которую мы переходим в качестве входных данных принимает титана (т.е. 'T) в качестве входных данных и урожайности урана (т.е.' U) в качестве выхода.

Опция вернулся

option:'T option -> 'U option 

Мы будем называть вывод функции карты "вариант". Таким образом, это «опция», которая возвращается с выполнением map Функция также является функцией как указано выше. Требуется Титановый вариант и дает Уран вариант.

Пример:

type String20 = String20 of string 

type Name = { First:String20 
       Last:String20 
       Suffix:String20 option } 

let tryCreateName (first:string) (last:string) (suffix:string option) = 

    let isValid = [first; last] 
        |> List.forall (fun x -> x.Length > 2 && x.Length <= 20) 

    if isValid then 
     Some { First = String20(first); 
       Last = String20(last); 
       Suffix = Option.map String20 suffix } 
    else None 

Как следующее выражение карта:

Option.map String20 suffix 

На основании приведенного выше выражения, где находится "возвращается функция" опции Titanium - >Уран опция?

+2

Мне было интересно, когда вы зададите этот вопрос. –

+1

Возвращаемые значения не имеют имен, поэтому функция 'map' имеет два параметра -' mapping: ('T ->' U) 'и' option: 'T option'. – Lee

+0

Хммм ... Я думал, что «->» означает выход. Следовательно, он находится между двумя параметрами. –

ответ

4

Во-первых, посмотрите на Option.map<'T,'U> Function (F#) и обратите внимание на

Выражение отображение F вх оценивает в соответствии с вх None -> None | Некоторые х -> Некоторые (f x).

Так что давайте преобразуем этот комментарий в рабочий код. Первая карта - это метод типа Option, но для упрощения мы сделаем его функцией вне типа и чтобы избежать конфликтов с другими функциями карты, мы дадим ему имя OptionMap.

let OptionMap = f inp = 
    match inp with 
    | None -> None 
    | Some x -> Some (f x) 

Теперь, чтобы получить подпись этой функции просто отправить его на F # Interactive

val OptionMap : f:('a -> 'b) -> inp:'a option -> 'b option 

и сделать типы очевидно, что мы будем вводить параметры функции.

let optionMap (f : ('a -> 'b)) (inp : 'a option) : 'b option = 
    match inp with 
    | None -> None 
    | Some x -> Some (f x) 

Теперь, чтобы проверить это, мы можем использовать

let (test : String20 option) = optionMap String20 (Some("something")) 
printfn "test: %A" test 
// test: Some (String20 "something") 

Так что случилось в OptionMap, что позволило этим работать

Если мы добавим некоторые операторы печати, пусть видит, что происходит

let optionMap (f : ('a -> 'b)) (inp : 'a option) : 'b option = 
    printfn "f: %A" f 
    printfn "inp: %A" inp 
    match inp with 
    | None -> None 
    | Some x -> 
      let result = Some (f x) 
    printfn "result: %A" result 
    result 

мы получаем

f: <fun:[email protected]> 
inp: Some "something" 
result: Some (String20 "something") 

мы видим, что е является функцией, которая является String20

Так как же String20 функция?

Если мы отправим String20 в F # Interactive, он даст.

So String20 - это функция, которая берет строку и возвращает тип String20. Это пахнет конструктором.

Давайте проверим это в F # interactive.

> let test1 = String20 "something";; 

val test1 : String20 = String20 "something" 

Конечно, String20 является конструктором, но мы специально не создать конструктор, как это делается в объектно-ориентированном мире.

Вы должны думать о типе, даже о разграниченном объединении как о конструкторах. Конструкторы специально не написаны, но существуют. Итак, String20 - это конструктор, который принимает одно значение, строку, которая является функцией с правильной сигнатурой типа для функции Option.map.

Я дал ответ гораздо более подробно, чтобы можно было изучить процесс решения проблем и взглянуть на внутреннюю работу как инструмент решения этих проблем.

Чтобы узнать больше о деталях нижнего уровня о том, как работает функциональное программирование, нужно понимать lambda calculus. Лучший способ узнать это - прочитать An Introduction To Functional Programming Through Lambda Calculus от Грега Майклсона и посмотреть информацию в lambda calculus tag.

Также, если вам нравится эта книга, вы должны купить копию вместо бесплатной версии.

+0

Спасибо, Гай Кодер. Меня зацепило оператора «->». Я думал, что это всегда означает выход. Я не знал, что это также разделитель аргументов внутри сигнатуры функции. –

+1

См. [Currying] (https://en.wikipedia.org/wiki/Currying) –

+0

У меня тоже были подобные проблемы. Только когда я нашел время, чтобы изучить все основы, это стало быстрее. Поскольку функциональное программирование похоже на математику, и когда учитель математики записывает последовательность преобразований на доске и пропускает несколько строк, это было очень запутанно. Когда пропущенные линии были добавлены, это имело больше смысла. Потратьте больше времени на основы, и он окупится. Я сам сделал [тысячи базовых тестов] (https://github.com/jack-pappas/fsharp-logic-examples/blob/master/FSharpx.Books.AutomatedReasoning.Tests/lib.fs) об основных функциях, и это действительно окупился. –

2

Как правило, если у вас есть функция T1 -> T2 -> ..., и вы применяете ее к одному параметру, вы получаете функцию T2 -> .... В случае Option.map, T1 сам по себе является функцией, но это не имеет никакого отношения к тому, как применяются аргументы.

Мне неловко вызывать функцию «option», строку «Titanium» и тип String20 «Uranium», поэтому я буду придерживаться имен типов.

Вы спрашиваете, где «возвращаемая функция», которая отображает параметр строки в параметр String20, находится в выражении Option.map String20 suffix.Это просто

Option.map String20 

С String20 строит String20 из строки, Option.map String20 это функция, которая отображает строку в String20, если он присутствует, и None в противном случае.

Если вы пишете Option.map String20 suffix, эта функция применяется к suffix, что является строковой опцией. Результатом этого выражения является опция String20.

2

String20 является корпус конструктор для String20 Дискриминационный случай Союза. Это функция с типом string -> String20. Таким образом, string занимает место 'T, а String20 занимает место 'U в поле mapping, которое вы указываете на Option.map.

4

Существует два способа взглянуть на него.

let f x y = x + y 
// val f: x:int -> y:int -> int 

Один из способов сказать, что функция f принимает два параметра, x типа int и y типа int и возвращает int. Поэтому я могу поставить два аргумента и получить результат:

let a = f 4 5 
// val a: int = 9 

Другой способ заключается в том, что функция принимает один параметр, x типа int, и возвращает другую функцию, которая принимает один параметр, y типа int, и возвращает int. Поэтому я могу поставить один аргумент и получить функцию как результат:

let b = f 4 
// val b: int -> int 

Математически это всегда второй способ - все функции являются функциями одного параметра. Это понятие очень удобно для программирования с функциями более высокого порядка. Но первый способ, как правило, более понятен людям, поэтому вы часто видите обсуждаемые функции, как будто они принимают несколько параметров.

Смежные вопросы