F # типов
Давайте начнем с самого начала.
F # использует двоеточие (:
) для обозначения типов вещей. Допустим, вы определили значение типа int
:
let myNumber = 5
F # Interactive поймет, что myNumber
является целым числом, и сообщит вам следующее:
myNumber : int
который читается как
myNumber
относится к типу int
F # функциональные типы
Пока все хорошо. Давайте введем что-то еще, функциональные типы . Функциональный тип - это просто тип функции . F # использует ->
для обозначения функционального типа. Эта стрелка символизирует, что то, что написано на его левой стороне, превращается в то, что написано на его правой стороне.
Давайте рассмотрим простую функцию, которая принимает один аргумент и преобразует его в один вывод. Примером такой функции будет:
isEven : int -> bool
Здесь вводится название функции (слева от :
) и ее тип. Эта строка может быть прочитана на английском языке как:
isEven
имеет функцию типа, которая преобразует int
в bool
.
Обратите внимание, что для правильного толкования того, что говорится, вы должны сделать короткую паузу сразу после того, как часть «имеет тип», а затем сразу прочитать остальную часть предложения, не останавливаясь.
В F # функции имеют значения
В F # функции (почти) не более особенные, чем обычные типы. Это вещи, которые вы можете передавать функциям, возвращать из функций, как bools, int или strings.
Так что если у вас есть:
myNumber : int
isEven : int -> bool
Вы должны рассматривать int
и int -> bool
как две сущности одного типа: типы. Здесь myNumber
- это значение типа int
, а isEven
- это значение типа int -> bool
(это то, что я пытаюсь символизировать, когда говорю о короткой паузе выше ).
Применение функции
Значения типов, которые содержат ->
, также называются функциями и имеют специальные полномочия: вы можете применять функцию к значению. Так, например,
isEven myNumber
означает, что вы применяете функцию с именем isEven
к значению myNumber
. Как вы можете ожидать, проверив тип isEven
, он вернет логическое значение. Если вы правильно внедрили isEven
, он, очевидно, вернет false
.
Функция, которая возвращает значение функционального типа
Давайте определим обобщенную функцию, чтобы определить, является ли целое число кратным некоторому другому целому числу. Мы можем представить, что тип нашей функции будет (скобки здесь, чтобы помочь вам понять, они могут или не могут присутствовать, они имеют особое значение):
isMultipleOf : int -> (int -> bool)
Как вы можете догадаться, это читается как:
isMultipleOf
имеет функцию типа (PAUSE), которая преобразует int
в (PAUSE) функцию, которая преобразует int
в bool
.
(здесь (ПАУЗА) обозначает паузы при чтении вслух).
Мы определим эту функцию позже. Перед этим посмотрим, как мы можем его использовать:
let isEven = isMultipleOf 2
F # Interactive ответит:
isEven : int -> bool
который читается как
isEven
относится к типу int -> bool
Здесь isEven
имеет тип int -> bool
, поскольку мы только что дали значение 2 (int
) isMultipleOf
, которое, как мы уже видели, преобразует int
в int -> bool
.
Мы можем рассматривать эту функцию isMultipleOf
как своего рода создателя функции .
Определение isMultipleOf
Итак, давайте теперь определим эту мистическую функцию создания функции.
let isMultipleOf n x =
(x % n) = 0
Полегче, да?
Если вы введете это в F # Interactive, он ответит:
isMultipleOf : int -> int -> bool
Где круглые скобки?
Обратите внимание, что здесь нет скобок. Это не особенно важно для вас сейчас. Просто помните, что стрелки ассоциативно правы . То есть, если у вас есть
a -> b -> c
Вы должны интерпретировать это как
a -> (b -> c)
право в право ассоциативно означает, что вы должны интерпретировать, как если бы были круглые скобки вокруг самого правого оператора. Итак:
a -> b -> c -> d
следует интерпретировать как
a -> (b -> (c -> d))
Использование isMultipleOf
Итак, как вы видели, мы можем использовать isMultipleOf
для создания новых функций:
let isEven = isMultipleOf 2
let isOdd = not << isEven
let isMultipleOfThree = isMultipleOf 3
let endsWithZero = isMultipleOf 10
F # Interactive ответит:
isEven : int -> bool
isOdd : int -> bool
isMultipleOfThree : int -> bool
endsWithZero : int -> bool
Но вы можете использовать его по-другому. Если вы не хотите (или должны) создавать новую функцию, вы можете использовать ее следующим образом:
isMultipleOf 10 150
Это вернет true
, так как 150 кратно 10. Это точно так же, как создать функцию endsWithZero
и затем применить ее к значению 150.
На самом деле, приложение функции остается ассоциативным , что означает, что строка выше должна интерпретироваться как:
(isMultipleOf 10) 150
То есть вы ставите круглые скобки вокруг крайнего левого приложения функции.
Теперь, если вы можете понять все это, ваш пример (который является каноническим CreateAdder
) должен быть тривиальным!
Некоторое время назад кто-то задал этот вопрос , который касается точно такой же концепции, но в Javascript. В своем ответе я приведу два канонических примера (CreateAdder, CreateMultiplier) inf Javascript, которые несколько более явны в отношении возврата функций.
Надеюсь, это поможет.