Подтвердить что ты не робот

Зачем нам нужен Control.Lens.Reified?

Зачем нам Control.Lens.Reified? Есть ли причина, по которой я не могу разместить Lens непосредственно в контейнере? Что означает reify?

4b9b3361

Ответ 1

Нам нужны оверенные линзы, потому что система типа Haskell является предикативной. Я не знаю технических подробностей о том, что это значит, но он запрещает такие типы, как

[Lens s t a b]

В некоторых целях приемлемо использовать

Functor f => [(a -> f b) -> s -> f t]

вместо этого, но когда вы достигнете этого, вы не получите Lens; вы получаете LensLike, специализирующийся на каком-то функторе или другом. ReifiedBlah newtypes позволяют вам поддерживать полный полиморфизм.

Оперативно, [ReifiedLens s t a b] - это список функций, каждый из которых принимает словарь Functor f, а forall f . Functor f => [LensLike f s t a b] - это функция, которая принимает словарь Functor f и возвращает список.

Что касается того, что означает "reify", то словарь скажет что-то, и это, кажется, переводится в довольно ошеломляющее разнообразие конкретных значений в Haskell. Так что не комментируйте это.

Ответ 2

Проблема заключается в том, что в Haskell тип абстракции и приложения полностью неявные; компилятор должен вставить их там, где это необходимо. Различные попытки создания "экспрессивных" расширений, когда компилятор сделал бы умные догадки, где их поставить, потерпели неудачу; поэтому самая безопасная вещь в конечном итоге опирается на правила Haskell 98:

  • Абстракции типа отображаются только на верхнем уровне определения функции.
  • Приложения типа появляются немедленно, когда в выражении используется переменная с полиморфным типом.

Итак, если я определяю простой объектив: [1]

lensHead f [] = pure []
lensHead f (x:xn) = (:xn) <$> f x

и использовать его в выражении:

[lensHead]

lensHead автоматически применяется к некоторому набору параметров типа; после чего он больше не является объективом, потому что он больше не является полиморфным в функторе. Вывод: выражение всегда имеет некоторый мономорфный тип; так что это не объектив. (Вы заметите, что функции lens принимают аргументы типа Getter и Setter, которые являются мономорфными типами, по тем же причинам. Но [Getter s a] не является списком линз, были специализированы только для геттеров.)

Что означает reify? Определение словаря "сделать реальным". "Обоснование" используется в философии, чтобы ссылаться на акт рассмотрения или рассмотрения чего-либо как реального (а не идеального или абстрактного). В программировании он имеет тенденцию ссылаться на то, что обычно не может рассматриваться как структура данных и представляет его как единое целое. Например, в действительно старых Lisps не использовались первоклассные функции; вместо этого вам пришлось использовать S-выражения для передачи "функций" и eval их, когда вам нужно было вызвать функцию. S-выражения представляли функции таким образом, что вы могли бы манипулировать в программе, которая называется reification.

В Haskell нам обычно не нужны такие сложные стратегии reification, как Lisp S-выражения, отчасти потому, что язык разработан, чтобы избежать необходимости в них; но поскольку

newtype ReifiedLens s t a b = ReifiedLens (Lens s t a b)

имеет тот же эффект, что и полиморфное значение и превращает его в истинное первоклассное значение, оно упоминается как reification.

Почему это работает, если выражения всегда имеют мономорфные типы? Хорошо, потому что расширение Rank2Types добавляет третье правило:

  • Абстракции типа встречаются на верхнем уровне аргументов для определенных функций с так называемыми типами ранга 2.

ReifiedLens является такой функцией ранга-2; поэтому, когда вы говорите

ReifiedLens l

вы получаете тип лямбда вокруг аргумента ReifiedLens, а затем l немедленно применяется к аргументу типа lambda. Итак, l эффективно просто расширяется. (Компиляторы свободны для eta-уменьшить это и просто использовать l напрямую).

Затем, когда вы скажете

f (ReifiedLens l) = ...

в правой части, l - это переменная с полиморфным типом, поэтому каждое использование l немедленно неявно присваивается любым аргументам типа, необходимым для выражения для проверки типа. Итак, все работает так, как вы ожидаете.

Другим способом думать является то, что если вы скажете

newtype ReifiedLens s t a b = ReifiedLens { unReify :: Lens s t a b }

две функции ReifiedLens и unReify действуют как явные операции абстракции типа и приложения; это позволяет компилятору определить, где вы хотите, чтобы абстракции и приложения проходили достаточно хорошо, чтобы проблемы с системами нечистоплотного типа не возникали.

[1] В терминологии lens это, по-видимому, называется чем-то иным, чем "линзой"; все мое знание линз происходит из презентации SPJ на них, поэтому я не могу проверить это. Точка остается, так как полиморфизм по-прежнему необходим, чтобы заставить его работать как геттер, так и сеттер.