2010-11-13 3 views
4

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

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

пусть Readline = Console.ReadLine()

и

пусть ReadLine() =() Console.ReadLine

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

пусть печати (текст: строка)() = Console.WriteLine текст

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

LET печать (текст: строка) = Console.WriteLine текст

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

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

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

спасибо всем за ответы, это ясно для меня сейчас. Что касается цитаты, мы оставим ее в покое.

+0

Если вы собираетесь на F # с C#, вы можете найти их полезными: http://lorgonblog.wordpress.com/2008/04/03/f-function-types-fun-with-tuples-and-currying/ и http: //lorgonblog.wordpress.com/2008/11/28/what-do-this-c-code-look-like-in-f-part-one-expressions-and-statements/ – Brian

+1

Самым запутанным аспектом блога является использование 'print 'как имя функции, когда лучшее имя -' makePrinter', так как оно принимает строку и возвращает функцию, которая будет печатать эту строку. – Brian

+0

Что касается цитаты, я не совсем уверен, что автор пытается сказать, поэтому я не могу помочь (это тоже не имеет для меня никакого смысла). Возможно, он просто пытается подчеркнуть тот факт, что существует разница между объявлениями _value_ и _function_ в F #. –

ответ

5

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

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

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

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

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

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

> 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! 

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

3

Это:

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

Использование каррирование,

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

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

let helloPrinter = makePrinter "hello" 

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

helloPrinter() 

На с другой стороны,

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

выходы «немедленно текст», если называется

print "hello" 

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

+0

@Brian: спасибо за исправление подписи типа – Frank

+0

Нет проблем (извините за выполнение большего редактирования, чем я изначально планировал) – Brian

Смежные вопросы