Подтвердить что ты не робот

F # Функции против значений

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

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

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

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

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

4b9b3361

Ответ 1

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

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

или это:

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

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

Currying and composition действительно полагаются на то, что все функции принимают один параметр и возвращают одно значение.

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

// 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 немного быстрее. Знание различия здесь может помочь вам написать более быстрый код.

Ответ 4

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

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/.