F # - создание делегатов
Вопрос
В настоящее время читаю серию постов в блоге о F #, ориентированных на программиста C #.Прямо сейчас я закончил читать часть 3 ( http://www.jelovic.com/weblog/?p=220 ) и остаюсь озадаченным.
Разница между
пусть readLine = Консоль.ReadLine ()
и
пусть readLine () = Консоль.ReadLine ()
достаточно ясно, но зачем нужно указывать две фигурные скобки - () - в следующей строке:
пусть печатается (текст :строка) () = Консоль.Текст строки записи
Разве компилятор не должен быть в состоянии определить, что вы объявляете печать делегата, опустив фигурные скобки, чтобы это выглядело следующим образом:
пусть печатается (текст :строка) = Консоль.Текст строки записи
Кроме того, следующая строка имела для меня мало смысла
Обычно, когда у вас есть функция, которая принимает параметры другого типа, компилятор может различать вызов функции и ссылку делегата, но для unit вы должны принудительно выполнить это.
Означает ли это, что когда параметры отличаются, компилятору безопасно предположить, что это вызов функции?
спасибо вам всем за ответы, теперь мне все ясно.Что касается цитаты, то мы оставим ее в покое.
Решение
Введение. Я думаю, что полезно сначала обсудить разницу в простом примере, поскольку это помогает понять, что такое "единица измерения".Первое объявление создает строковое значение (и немедленно вызывает 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 #, но оно не очень полезно.Это означает, что функция будет вызвана только тогда, когда вы предоставите ей некоторую строку для печати, а также дополнительное значение "единица измерения".Вы можете назвать это так:
print "Hello" ()
Даже без дополнительного параметра "единица измерения" это была бы функция (в отличие от значения), поэтому добавление дополнительного параметра не помогает (вы всегда создаете функцию, которую можно вызывать для печати разных строк).
Все еще есть случаи, когда это заявление может быть интересным.Например, вы можете вызвать функцию только со строкой в качестве параметра.В этом случае в результате вы получите функцию.Возвращаемая функция примет единицу измерения и выведет строку:
let f = print "Hello" // doesn't print anything
f () // prints "Hello"
f () // prints "Hello" again!
Итак, компилятор позволяет вам использовать "единичные" значения как любые другие значения в языке.Сюда входят варианты использования, которые на первый взгляд могут показаться немного незнакомыми (и не очень полезными), но могут иметь смысл в каком-то сценарии.
Другие советы
Этот:
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) может быть повторно использован много раз.
Используя карри,
let makePrinter (text : string) () = Console.WriteLine text
Давайте создадим функцию, которая всегда печатает определенную строку, например,
let helloPrinter = makePrinter "hello"
дает «привет» просто призвать
helloPrinter ()
С другой стороны,
let print (text : string) = Console.WriteLine text
немедленно выводит «текст», если они называются
print "hello"
и возвращает (), а не функция типа unit -> unit
Как в первом, Curred Case.