Должен ли NFData иметь дуал?
В Haskell есть тип, который имеет следующую форму:
class NFData a
where
rnf :: a -> ()
Типы, которые больше похожи на данные, чем на функциональные, могут быть оснащены экземплярами
NFData
. Каждый такой экземпляр тщательно анализирует данное значение типа и все, что он транзитивно содержит. Это заставляет заглушки и взрывает скрытые основания.
NB: Как ни странно, даже «функциональные» типы снабжены экземплярами, хотя на самом деле они не приводят свой аргумент к нормальной форме.
Так обстоит дело с анализом случая. Но иногда полезно принять двойную точку зрения и подумать о вещах, которые больше похожи на кодированные, чем на данные. Вместо того, чтобы анализировать сумму до ее случаев, мы хотели бы построить запись до ее полей.
Итак, не имея никакого реального представления о том, о чем я говорю, я мог бы, таким образом, блуждать, поворачивая любые стрелы, с которыми я сталкиваюсь, и добавляя несколько вариантов выбора.
Co
s:
class NFCodata a
where
cornf :: () -> a
Я ожидал бы экземпляры следующей формы для типов, представляющих конечные произведения нестрогих полей (грубо говоря, типы с «одним конструктором»):
instance NFCodata ()
where
cornf () = ()
instance NFCodata a => NFCodata (Solo a)
where
cornf () = Solo $ cornf ()
instance (NFCodata a, NFCodata b) => NFCodata (a, b)
where
-- you get the idea
И для всех типов данных с меньшим / более чем одним конструктором я ожидал бы экземпляр следующей формы:
instance NFCodata Void
where
cornf () = undefined
instance NFCodata (Either a b)
where
cornf () = undefined
instance NFCodata Int
where
cornf () = undefined
-- ...
NB: Возможно, это немного подозрительно, но если мы не дадим эти экземпляры, мы перейдем только к типам, изоморфным
()
имея экземпляр.
Конечный результат должен заключаться в том, что производный экземпляр для такого типа:
data Foo = Foo
{ bar :: Bar
, baz :: Baz
}
deriving stock Generic
deriving anyclass NFCodata
data Bar = Bar
{ someInt :: Int
, someString :: String
}
deriving stock Generic
deriving anyclass NFCodata
data Baz = Baz
deriving stock Generic
deriving anyclass NFCodata
ведет себя так:
-- $> cornf () :: Foo
-- => Foo
-- { bar = Bar
-- { someInt = undefined
-- , someString = undefined
-- }
-- , baz = Baz
-- }
Идея в том, что линзы можно использовать для
Foo
,
Bar
и т.д., чтобы заполнить содержимое этого пустого корешка.
Итак ... вопросы:
- Имеет ли смысл иметь такой класс? Есть ли уже способ получить "корешок" типа codata с дном для его содержимого? Делает
NFCodata
уже существуют в какой-то другой, более принципиальной форме? - Есть ли в каком-то строгом смысле аналогия между данными {NF} и {NF}Codata?
- Действительно ли «NF» - правильный префикс для использования в «NFCodata»? Есть ли здесь более подходящий математический термин (и, что более важно, способ мышления)?