Я не понимаю, что такое «подъем». Должен ли я сначала понять монады, прежде чем понять, что такое «лифт»? (Я тоже совершенно не осведомлен о монадах :) Или кто-то может объяснить мне это простыми словами?
138
Я не понимаю, что такое «подъем». Должен ли я сначала понять монады, прежде чем понять, что такое «лифт»? (Я тоже совершенно не осведомлен о монадах :) Или кто-то может объяснить мне это простыми словами?
Ответы:
Подъем - это скорее шаблон проектирования, чем математическая концепция (хотя я ожидаю, что кто-то здесь сейчас опровергнет меня, показав, что подъемы - это категория или что-то в этом роде).
Обычно у вас есть некоторый тип данных с параметром. Что-то вроде
Предположим, вы обнаружите, что во многих случаях используются
Foo
числовые типы дублей (Int
иDouble
т. Д.), И вам по-прежнему приходится писать код, который разворачивает эти числа, добавляет или умножает их, а затем упаковывает их обратно. Вы можете замкнуть это, написав один раз код развертки и переноса. Эта функция традиционно называется «лифт», потому что она выглядит так:Другими словами, у вас есть функция, которая принимает функцию с двумя аргументами (например,
(+)
оператор) и превращает ее в эквивалентную функцию для Foos.Так что теперь вы можете написать
Редактировать: больше информации
Вы можете, конечно , есть
liftFoo3
,liftFoo4
и так далее. Однако это часто не является необходимым.Начните с наблюдения
Но это точно так же, как
fmap
. Так что вместо тогоliftFoo1
, чтобы написатьЕсли вы действительно хотите полной регулярности, вы можете сказать
Если вы можете превратить
Foo
в функтор, возможно, вы сможете сделать его аппликативным функтором. На самом деле, если вы можете написать,liftFoo2
аппликативный экземпляр выглядит так:(<*>)
Оператор Foo имеет типОн применяет упакованную функцию к упакованному значению. Так что, если вы можете реализовать,
liftFoo2
то вы можете написать это с точки зрения этого. Или вы можете реализовать это напрямую и не беспокоитьсяliftFoo2
, потому чтоControl.Applicative
модуль включает в себяа также есть
liftA
иliftA3
. Но вы на самом деле не используете их очень часто, потому что есть другой операторЭто позволяет вам написать:
Термин
myFunction <$> arg1
возвращает новую функцию в Foo. Это, в свою очередь, может быть применено к следующему аргументу, используя(<*>)
, и так далее. Так что теперь вместо того, чтобы иметь функцию лифта для каждой арности, у вас есть цепочка аппликаций.источник
lift id == id
иlift (f . g) == (lift f) . (lift g)
.id
и.
являются стрелкой-идентификатором и композицией стрелки какой-либо категории, соответственно. Обычно , когда речь идет о Haskell, категория в вопросе «Hask», чьи стрелы Haskell функции (другими словами,id
и.
относятся к функциям Haskell вы знаете , и любовь).instance Functor Foo
, не такinstance Foo Functor
ли? Я бы отредактировал себя, но я не уверен на 100%.Пол и Яирчу - хорошие объяснения.
Я хотел бы добавить, что поднимаемая функция может иметь произвольное количество аргументов и что они не обязательно должны быть одного типа. Например, вы также можете определить liftFoo1:
В общем случае, снятие функций, которые принимают 1 аргумент, фиксируется в классе типов
Functor
, и операция подъема называетсяfmap
:Обратите внимание на сходство с
liftFoo1
типом s. На самом деле, если у вас естьliftFoo1
, вы можете сделатьFoo
экземплярFunctor
:Кроме того, обобщение поднятия на произвольное количество аргументов называется аппликативным стилем . Не стоит углубляться в это, пока вы не поймете отмену функций с фиксированным числом аргументов. Но когда вы это сделаете, в Learn the Haskell есть хорошая глава по этому вопросу. Typeclassopedia еще один хороший документ , который описывает Functor и Аппликативные (а также другие классы типов, прокрутки вниз к правому главе в этом документе).
Надеюсь это поможет!
источник
Давайте начнем с примера (для более ясного представления добавлен пробел):
liftA2
преобразует функцию простых типов в функцию тех же типов, завернутую вApplicative
, например, спискиIO
и т. д.Еще один общий лифт
lift
отControl.Monad.Trans
. Он преобразует монадическое действие одной монады в действие трансформированной монады.В общем, «лифт» поднимает функцию / действие в «обернутый» тип (поэтому исходная функция начинает работать «под обертками»).
Лучший способ понять это, монады и т. Д. И понять, почему они полезны, - это, вероятно, написать код и использовать его. Если есть что-то, что вы ранее запрограммировали, что, как вы подозреваете, может извлечь из этого пользу (т.е. это сделает этот код короче и т. Д.), Просто попробуйте это, и вы легко поймете эту концепцию.
источник
Подъем - это концепция, которая позволяет вам преобразовать функцию в соответствующую функцию в другой (обычно более общей) настройке.
взгляните на http://haskell.org/haskellwiki/Lifting
источник
Согласно этому блестящему уроку , функтор - это некоторый контейнер (например
Maybe<a>
,List<a>
илиTree<a>
который может хранить элементы какого-то другого типаa
). Я использовал нотацию обобщений Java<a>
для типов элементовa
и представляю элементы как ягоды на деревеTree<a>
. Есть функцияfmap
, которая принимает функцию преобразования элементаa->b
и контейнерfunctor<a>
. Это относитсяa->b
к каждому элементу контейнера, эффективно превращающему его вfunctor<b>
. Когда только первый аргумент подается,a->b
,fmap
ожидает , покаfunctor<a>
. То есть,a->b
только поставка превращает эту функцию уровня элемента в функцию,functor<a> -> functor<b>
которая работает над контейнерами. Это называется подъемомфункции. Поскольку контейнер также называется функтором , Функторы, а не Монады, являются предпосылкой для подъема. Монады своего рода «параллельны» подъему. Оба полагаются на понятие Функтора и делаютf<a> -> f<b>
. Разница в том, что лифт используетсяa->b
для преобразования, тогда как Monad требует от пользователя определенияa -> f<b>
.источник
r
к типу (давайте использоватьc
для разнообразия), являются Функторами. Они не «содержат» ничегоc
. В этом случае fmap - это композиция функций, которая принимаетa -> b
функцию иr -> a
единицу, чтобы дать вам новуюr -> b
функцию. Все еще нет контейнеров. Также, если бы я мог, я бы отметил это снова для последнего предложения.fmap
это функция, которая ничего не «ждет»; «Контейнер», являющийся Функтором, - вот и вся точка подъема. Кроме того, монады - это, во всяком случае, двойная идея для подъема: монада позволяет вам использовать то, что было поднято несколько раз подряд, как если бы оно было поднято только один раз - это больше известно как выравнивание .To wait
,to expect
,to anticipate
являются синонимами. Говоря «функция ожидает», я имел в виду «функция ожидает».b = 5 : a
иf 0 = 55
f n = g n
оба включают псевдо-мутирование «контейнера». Кроме того, тот факт, что списки, как правило, полностью хранятся в памяти, тогда как функции, как правило, хранятся в виде расчета. Но запоминание / монорфные списки, которые не сохраняются между вызовами, разрушают эту идею.