Вопрос

Я уже некоторое время пытаюсь вникнуть в F #, но меня все время что-то откладывает.Почему?

Потому что независимо от того, на какой ресурс для начинающих я пытаюсь обратить внимание, я вижу очень простые примеры, которые начинают использовать оператор ->.

Однако я пока нигде не нашел четкого простого объяснения того, что означает этот оператор.Как будто это должно быть настолько очевидно, что не нуждается в объяснениях даже для полных новичков.

Следовательно, я, должно быть, действительно тупой, или, возможно, меня сдерживает почти 3 десятилетия предыдущего опыта.

Может кто-нибудь, пожалуйста, объяснить это или указать на действительно доступный ресурс, который это объясняет?

Это было полезно?

Решение

'->' не является оператором.Он появляется в синтаксисе F # в нескольких местах, и его значение зависит от того, как он используется как часть более крупной конструкции.

Внутри типа '->' описывает типы функций, как люди описали выше.Например

let f : int -> int = ...

говорит, что 'f' - это функция, которая принимает значение int и возвращает значение int.

Внутри лямбда-выражения ("вещь, которая начинается с ключевого слова 'fun'"), '->' - это синтаксис, который отделяет аргументы от тела.Например

fun x y -> x + y + 1

является выражением, которое определяет функцию с двумя аргументами в данной реализации.

Внутри конструкции "match" '->' - это синтаксис, который отделяет шаблоны от кода, который должен выполняться, если шаблон соответствует.Например, в

match someList with
| [] -> 0
| h::t -> 1

элементы слева от каждого '->' - это шаблоны, а элементы справа - это то, что произойдет, если шаблон слева был сопоставлен.

Трудность в понимании может корениться в ошибочном предположении, что '->' - это "оператор" с единственным значением.Аналогией может быть "." в C #, если вы никогда раньше не видели никакого кода, и попробуйте проанализировать оператор ".", основываясь на просмотре "obj.Method" и "3.14" и "System.Коллекции", вы можете сильно запутаться, потому что этот символ имеет разные значения в разных контекстах.Однако, как только вы достаточно освоите язык, чтобы распознать эти контексты, все станет ясно.

Другие советы

По сути, это означает "сопоставляет с".Прочтите это таким образом или как "преобразуется в" или что-то в этом роде.

Итак, из F# через 20 минут Учебник,

> List.map (fun x -> x % 2 = 0) [1 .. 10];;
val it : bool list
= [false; true; false; true; false; true; false; true; false; true]

Код (fun i -> i % 2 = 0) определяет анонимную функцию, называемую лямбда выражение, которое имеет параметр x и функция возвращает результат "x % 2 = 0", то есть независимо от того, является ли x четным.

Первый вопрос - знакомы ли вы с лямбда-выражениями в C #?Если это так, то -> в F # совпадает с => в C # (я думаю, вы прочитали, что это "переходит в").

Оператор -> также можно найти в контексте сопоставления с шаблоном

match x with
| 1 -> dosomething
| _ -> dosomethingelse

Я не уверен, является ли это также лямбда-выражением или чем-то еще, но я думаю, что 'goes to' все еще остается в силе.

Возможно, то, что вы на самом деле имеете в виду, - это "загадочные" ответы анализатора F #:

> let add a b = a + b
val add: int -> int -> int

Это означает (как объясняется в большинстве примеров), что add - это 'val', который принимает два целых числа и возвращает значение int.Для меня это было совершенно непрозрачно с самого начала.Я имею в виду, откуда мне знать, что add - это не значение, которое принимает одно значение int и возвращает два целых числа?

Ну, дело в том, что в каком-то смысле это так и есть.Если я добавлю только один int, я получу обратно (int -> int):

> let inc = add 1
val inc: int -> int

Это (приготовление карри) - одна из вещей, которая делает F # таким сексуальным, на мой взгляд.

Для получения полезной информации о F # я обнаружил, что блоги гораздо более полезны, чем любая официальная "документация":Вот несколько имен, на которые стоит обратить внимание

(a -> b) означает "функция от a до b".В аннотации типа он обозначает тип функции.Например, f :(int -> String) означает, что f ссылается на функцию, которая принимает целое число и возвращает строку.Он также используется в качестве конструктора таких значений, как в

val f : (int -> int) = fun n -> n * 2

который создает значение, представляющее собой функцию от некоторого числа n до этого же числа, умноженного на два.

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

' ->' означает функцию.

'a -> 'b - это функция, которая принимает 'a и возвращает 'b

('a * 'b) -> ('c * 'd) - это функция, которая принимает кортеж типа ('a, 'b) и возвращает кортеж типа ('c, 'd).Например, int/string возвращает float/char .

Где это становится интересным, так это в каскадном случае 'a -> 'b -> 'c.Это функция, которая принимает 'a и возвращает функцию ('b -> 'c), или функция, которая принимает 'b -> 'c.

Так что, если вы напишете:пусть f x y z = ()

Тип будет иметь вид f :'a -> 'b -> 'c -> unit, поэтому, если бы вы применили только первый параметр, результатом была бы функция curried 'b -> 'c ->'unit.

От Майкрософт:

Типы функций - это типы, присвоенные значениям функций первого класса и записываемые int -> int.Они похожи на типы делегатов .NET, за исключением того, что им не присваиваются имена.Все функции F # идентификаторы могут использоваться как первоклассные значения функций, так и анонимные значения функций могут быть созданы с помощью (fun ...-> ...) форма выражения.

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

Для тех, кто знаком с пониманием C # -> быть таким же, как => выражение lamba, является хорошим первым шагом.Это использование является :-

fun x y -> x + y + 1

Может быть понято как эквивалент:-

(x, y) => x + y + 1;

Однако ясно, что -> имеет более фундаментальное значение, которое вытекает из концепции, что функция, которая принимает два параметра, таких как приведенные выше, может быть сведена (это правильный термин?) к серии функций, принимающих только один параметр.

Следовательно, когда вышеизложенное описано примерно так:-

Int -> Int -> Int

Это действительно помогло узнать, что -> является правильным ассоциативным, следовательно, вышесказанное можно рассмотреть:-

Int -> (Int -> Int)

Ага!У нас есть функция, которая принимает Int и возвращает (Int -> Int) (каррированная функция?).

Также помогло объяснение, что -> также может отображаться как часть определения типа.(Int -> Int) - это тип любой функции, которая принимает значение Int и возвращает значение Int.

Также полезно -> появляется в другом синтаксисе, таком как matching, но там оно не имеет того же значения?Это правильно?Я не уверен, что это так.Я подозреваю, что это имеет то же значение, но у меня пока нет словарного запаса, чтобы выразить это.

Обратите внимание, что целью этого ответа является не создание дополнительных ответов, а совместное редактирование вами, людьми, для создания более окончательного ответа.В конечном счете, было бы хорошо, чтобы все неопределенности и неточности (такие как этот абзац) были удалены и добавлены лучшие примеры.Давайте попробуем сделать этот ответ как можно более доступным для непосвященных.

В контексте определения функции это похоже на => из лямбда-выражения в C # 3.0.

F#: let f = fun x -> x*x
C#: Func<int, int> f = x => x * x;

Тот Самый -> в F # также используется при сопоставлении с образцом, где это означает:если выражение совпадает с частью между | и ->, тогда что же будет после -> должно быть возвращено в результате:

let isOne x = match x with
 | 1 -> true
 | _ -> false

Хорошая особенность таких языков, как Haskell (он очень похож на F #, но я не знаю точного синтаксиса - это должно помочь вам понять ->, хотя), заключается в том, что вы можете применять только части аргумента для создания приготовленный с карри функции:

adder n x y = n + x + y

Другими словами:"назовите мне три вещи, и я сложу их вместе".Когда вы добавляете в него числа, компилятор выводит типы n x и y .Допустим, вы пишете

adder 1 2 3

Тип 1, 2 и 3 - Int .Следовательно:

adder :: Int -> Int -> Int -> Int

То есть, дайте мне три целых числа, и я, в конце концов, стану целым числом, или то же самое, что сказать:

five :: Int
five = 5

Но вот что самое приятное!Попробуй это:

add5 = adder 5

Как вы помните, adder принимает значение int, int, int и возвращает вам значение int.Однако, как вы вскоре увидите, это не вся правда.Фактически, add5 будет иметь такой тип:

add5 :: Int -> Int -> Int

Это будет выглядеть так, как если бы вы "отклеили" от целых чисел (самое левое) и приклеили его непосредственно к функции.Присмотревшись повнимательнее к сигнатуре функции, мы замечаем, что -> являются правоассоциативными, т.е.:

addder :: Int -> (Int -> (Int -> Int))

Это должно сделать все совершенно ясным:когда вы даете сумматору первое целое число, оно вычисляет то, что находится справа от первой стрелки, или:

add5andtwomore :: Int -> (Int -> Int)
add5andtwomore = adder 5

Теперь вы можете использовать add5andtwomore вместо "сумматор 5".Таким образом, вы можете применить другое целое число, чтобы получить (скажем) "add5and7andonemore".:

add5and7andonemore :: Int -> Int
add5and7andonemore = adder 5 7

Как вы видите, add5and7andonemore хочет получить именно другой аргумент, и когда вы даете ему один, он внезапно становится целым числом!

  > add5and7andonemore 9
 => ((add5andtwomore) 7) 9
 => ((adder 5) 7) 9)
<=> adder 5 7 9

Подставляя параметры сумматора (n x y) в (5 7 9), получаем:

  > adder 5 7 9 = 5 + 7 + 9
 => 5 + 7 + 9
 => 21

На самом деле, plus - это также просто функция, которая принимает значение int и возвращает вам другое значение int, так что приведенное выше действительно больше похоже:

  > 5 + 7 + 9
 => (+ 5 (+ 7 9))
 => (+ 5 16)
 => 21

Вот так!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top