F # - создание делегатов - PullRequest
       30

F # - создание делегатов

4 голосов
/ 13 ноября 2010

В настоящее время читаю серию постов на F #, нацеленных на программиста C #. Прямо сейчас я закончил читать часть 3 (http://www.jelovic.com/weblog/?p=220) и остался озадаченным.

Разница между

let readLine = Console.ReadLine ()

и

let readLine () = Console.ReadLine ()

достаточно ясно, но зачем указывать две скобки - () - в следующей строке:

let print (text: string) () = Console.WriteLine text

Если компилятор не сможет определить, что вы объявляете печать делегата, пропустив фигурные скобки, он будет выглядеть следующим образом:

let print (text: string) = Console.WriteLine text

Кроме того, следующая строка не имела для меня никакого смысла

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

Значит ли это, что когда параметры различаются, компилятору безопасно предполагать, что это вызов функции?

спасибо всем за ответы, теперь мне это понятно. Что касается цитаты, мы оставим это.

Ответы [ 3 ]

5 голосов
/ 13 ноября 2010

Введение. Я думаю, что сначала полезно обсудить разницу в простом примере, поскольку это помогает понять, что такое "единичное" значение.Первое объявление создает строковое значение (и немедленно вызывает ReadLine для получения ввода от пользователя):

> let readLine = Console.ReadLine ();;
val readLine : string

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

Параметр «unit» - это просто способ создания функции, которая принимает что-то в качестве аргумента.«Единица» имеет только одно значение, записанное как (), поэтому оно не представляет никакой информации - только тот факт, что есть некоторый параметр:

> let readLine () = Console.ReadLine ();;
val readLine : unit -> string

Ваш вопрос. Чтобы посмотреть на ваш пример с дополнительными скобками.Это создает функцию, которая принимает строку в качестве первого параметра и принимает дополнительное значение «единицы» в качестве второго параметра.Это видно из сигнатуры типа:

> let print (text : string) () = Console.WriteLine text 
val print : string -> unit -> unit

Это допустимое объявление F #, но оно не очень полезно.Это означает, что функция будет вызываться только тогда, когда вы дадите ей строку для печати, а также дополнительное значение «unit».Вы можете назвать это так:

print "Hello" ()

Даже без дополнительного параметра «unit», это будет функция (в отличие от значения), поэтому добавление дополнительного параметра не поможет (вымы всегда создаем функцию, которую можно вызывать для печати разных строк).

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

let f = print "Hello" // doesn't print anything
f ()                  // prints "Hello"
f ()                  // prints "Hello" again!

Итак, компилятор позволяет использовать значения «единицы» как любые другие значения в языке.Это включает использование, которое на первый взгляд может показаться немного незнакомым (и не очень полезным), но может иметь смысл в некотором сценарии.

3 голосов
/ 13 ноября 2010

Это:

let print (text : string) = Console.WriteLine text

создает метод для печати, например:

print "hi" // prints "hi" in the console

где:

let print (text : string) () = Console.WriteLine text

производит метод для печати определенной строки, такой как:

let printHi = print "hi" // Does NOT print a string to the console

printHi () // But now this does print "hi" :)
printHi () // And this...

Таким образом, по сути, это фабрика "печать специфической строки X в консольную функцию", результат (ex printHi) которой можно многократно использовать.

2 голосов
/ 13 ноября 2010

Используя карри,

let makePrinter (text : string) () = Console.WriteLine text

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

let helloPrinter = makePrinter "hello"

дает "привет", просто позвонив

helloPrinter ()

С другой стороны,

let print (text : string) = Console.WriteLine text

сразу выводит «текст», если вызван

print "hello"

и return (), а не функция типа unit -> unit, как в первом случае с карри.

...