#f#
#f#
Вопрос:
Я читаю книгу «F # для разработчиков C #» Тао Лю. На странице 139 есть пример шаблона наблюдателя. Я не уверен, что Microsoft press или Tao позволят мне опубликовать полный список. Но вот часть, которую я пытаюсь обдумать.
// subscribe to a notification function
member this.Subscribe notifyFunction =
let wrap f i = f i ; i
notify <- wrap notifyFunction >> notify
в частности, let wrap f i = f i; i
Я знаю, что точка с запятой является разделителем для следующего оператора, поэтому i
после точки с запятой само по себе указывает на то, что это возвращаемое значение Subscribe
Похоже, что wrap — это функция, которая принимает f и i в качестве аргументов. f является функцией, которая принимает один аргумент, и в определении wrap f вызывается с i в качестве аргумента.
В следующей строке wrap поставляется с одной составной функцией вместо двух аргументов.
Может кто-нибудь помочь мне понять это? Я посмотрел это в FSI и увидел следующее
val wrap : f:('a -> unit) -> i:'a -> 'a
Мне кажется, что wrap
у него есть два аргумента: один — это f
функция a, в которой a является типом, полученным из использования, и ничего не возвращает, второй аргумент wrap
имеет сам тип a, который снова выводится из использования, а wrap возвращает значение типа a .
Вся эта комбинация всего сбивает меня с толку. Может кто-нибудь дать мне простой способ понять это?
Ответ №1:
Ваш анализ wrap
верен: это просто способ подтолкнуть некоторый побочный эффект к функции идентификации (имхо, немного пахнет)
Я думаю, что лучший способ понять эту функцию может быть:
let wrap (action : 'a -> unit) : 'a -> 'a =
fun a -> action a
a
Следующая строка
notify <- wrap notifyFunction >> notify
очень странно — это похоже x = x 1
на то, что он изменяет notify
функцию (должна быть изменяемой переменной?) Для вызова notifyFunction
, прежде чем она будет делать то, что делала раньше.
Не видя остальной части кода, я могу только предполагать: я думаю notify
, начинается с того, что просто появляется что-то вроде
let mutable notify = fun _ -> ()
Теперь всякий раз, когда вы впервые вызываете Subscripe
действие f: 'a -> ()
, код будет меняться notify
, чтобы быть эквивалентным этому:
let notify a =
f a
()
Второй вызов с f'
помощью даст вам нечто эквивалентное этому:
let notify a =
f' a
f a
()
и так далее…
Это будет работать, но, пожалуйста: не делайте ничего подобного — это нечитаемо, и это совсем не так, как вы должны обращаться с вещами в F#
Комментарии:
1. У вас довольно проницательные навыки. Вы получили объявление notify совершенно правильно
2. не нужно много навыков… все дело в типах 😉
3. вы согласны с ответом или есть что-то, чего вы не понимаете?
4. Wrap может использоваться для ведения журнала каждый раз, когда запускается уведомление или что-то подобное. Конечно, есть случаи, когда этого не следует делать таким образом, но я не думаю, что это изначально плохо.
5. да — но не пишите это так, чтобы вы не могли видеть, что он делает — в приведенном здесь примере это «волшебная» функция, но отступ скрыт неправильным наименованием и отсутствием подписи типа (всегда указывайте подписи для функций верхнего уровня и важных функций) -было бы понятнее, если бы warp здесь напрямую использовал функцию notifiyFunction и имел имя
prepend
или что-то в этом роде — я добавлю свой ответ, чтобы сделать это немного понятнее