Функции F # против значений - PullRequest
16 голосов
/ 24 августа 2010

Это довольно простой вопрос, и я просто хотел проверить, имеет ли смысл то, что я делаю и как я интерпретирую F #. Если у меня есть заявление

let printRandom = 
  x = MyApplication.getRandom()
  printfn "%d" x
  x

Вместо создания printRandom в качестве функции F # запускает ее один раз, а затем присваивает ей значение. Итак, теперь, когда я вызываю printRandom, вместо того, чтобы получить новое случайное значение и распечатать его, я просто получаю то, что было возвращено в первый раз. Я могу обойти это мое определение так:

let printRandom() = 
  x = MyApplication.getRandom()
  printfn "%d" x
  x

Это правильный способ провести это различие между беспараметрическими функциями и значениями? Это кажется мне менее чем идеальным. Влияет ли это на карри, композицию и т. Д.?

Ответы [ 4 ]

19 голосов
/ 24 августа 2010

Правильный взгляд на это заключается в том, что в F # нет такого понятия, как функции без параметров.Все функции должны принимать параметр, но иногда вам все равно, что это такое, поэтому вы используете () (значение типа singleton).Вы также можете создать такую ​​функцию:

let printRandom unused = 
  x = MyApplication.getRandom()
  printfn "%d" x
  x

или вот так:

let printRandom _ = 
  x = MyApplication.getRandom()
  printfn "%d" x
  x

Но () - это способ по умолчанию выразить, что вы не используете параметр.Он выражает этот факт вызывающей стороне, потому что тип unit -> int не 'a -> int;а также читателю, потому что сайт вызова printRandom () не printRandom "unused".

На самом деле каррирование и компоновка основаны на том факте, что все функции принимают один параметр и возвращают одно значение.

Между прочим, самый распространенный способ записи вызовов с модулем - с пробелом, особенно у не .NET-родственников F #, таких как Caml, SML и Haskell.Это потому, что () - это одноэлементное значение, а не синтаксическая вещь, как в C #.

8 голосов
/ 24 августа 2010

Ваш анализ верен.

Первый экземпляр определяет значение, а не функцию.Я признаю, что это несколько раз поймало меня, когда я начал с F #.Исходя из C #, кажется очень естественным, что выражение присваивания, которое содержит несколько операторов, должно быть лямбда-выражением и, следовательно, оценкой задержки.

Это просто не тот случай в F #.Утверждения могут быть почти произвольно вложенными (и это требует наличия локально ограниченных функций и значений).Как только вы освоитесь с этим, вы начнете рассматривать его как преимущество, поскольку вы можете создавать функции и продолжения, которые недоступны для остальной части функции.

Второй подход - это стандартный способ создания функции, которая логически не принимает аргументов.Я не знаю точной терминологии, которую команда F # использовала бы для этого объявления (возможно, функция, принимающая единственный аргумент типа unit).Поэтому я не могу комментировать, как это повлияет на карри.

7 голосов
/ 24 августа 2010

Это правильный способ провести это различие между беспараметрическими функциями и значениями?Это кажется мне менее чем идеальным.Имеет ли это последствия в карринге, композиции и т. Д.?

Да, то, что вы описываете, правильно.

Для чего оно стоит, у него есть очень интересное следствие, способное частично оценить функциипо декларации.Сравните эти две функции:

// val contains  : string -> bool
let contains =
    let people = set ["Juliet"; "Joe"; "Bob"; "Jack"]
    fun person -> people.Contains(person)

// val contains2 : string -> bool
let contains2 person =
    let people = set ["Juliet"; "Joe"; "Bob"; "Jack"]
    people.Contains(person)

Обе функции дают идентичные результаты, contains создает набор сотрудников при объявлении и использует его повторно, тогда как contains2 создает набор сотрудников при каждом вызове функции.Конечный результат: contains немного быстрее.Таким образом, зная различие здесь, вы можете написать более быстрый код.

3 голосов
/ 25 августа 2010

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

let foo =
    printfn "This runs at startup"
    (fun () -> printfn "This runs every time you call foo ()")

Я только что написал об этом в блоге сообщение на http://blog.wezeku.com/2010/08/23/values-functions-and-a-bit-of-both/.

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