Должен ли NFData иметь дуал?

В Haskell есть тип, который имеет следующую форму:

      class NFData a
  where
  rnf :: a -> () 

Типы, которые больше похожи на данные, чем на функциональные, могут быть оснащены экземплярами NFData. Каждый такой экземпляр тщательно анализирует данное значение типа и все, что он транзитивно содержит. Это заставляет заглушки и взрывает скрытые основания.

NB: Как ни странно, даже «функциональные» типы снабжены экземплярами, хотя на самом деле они не приводят свой аргумент к нормальной форме.

Так обстоит дело с анализом случая. Но иногда полезно принять двойную точку зрения и подумать о вещах, которые больше похожи на кодированные, чем на данные. Вместо того, чтобы анализировать сумму до ее случаев, мы хотели бы построить запись до ее полей.

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

      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и т.д., чтобы заполнить содержимое этого пустого корешка.


Итак ... вопросы:

  1. Имеет ли смысл иметь такой класс? Есть ли уже способ получить "корешок" типа codata с дном для его содержимого? Делает NFCodata уже существуют в какой-то другой, более принципиальной форме?
  2. Есть ли в каком-то строгом смысле аналогия между данными {NF} и {NF}Codata?
  3. Действительно ли «NF» - правильный префикс для использования в «NFCodata»? Есть ли здесь более подходящий математический термин (и, что более важно, способ мышления)?

0 ответов

Другие вопросы по тегам