Первоклассная прелюдия (зав. Головой)

Я пытаюсь преобразовать несколько проектов в classy-prelude в данный момент. В то время как большая часть поведения кажется мне довольно простой, (head . head) дает загадочные ошибки в простом 2D-списке.

Рассмотрим следующую сессию GHCi:

Prelude> (head . head) [[1,2],[3,4]]
1

Давайте попробуем это с ghci -XNoImplicitPrelude а также classy-prelude:

> import ClassyPrelude
ClassyPrelude> (head . head) [[1,2],[3,4]]

<interactive>:10:1:
    Couldn't match type `MinLen (Succ nat1) mono1' with `[[t0]]'
    Expected type: [[t0]] -> Element mono0
      Actual type: MinLen (Succ nat1) mono1 -> Element mono0
    The function `head . head' is applied to one argument,
    but its type `MinLen (Succ nat1) mono1 -> Element mono0'
    has only one
    In the expression: (head . head) [[1, 2], [3, 4]]
    In an equation for `it': it = (head . head) [[1, 2], [3, 4]]

Я предполагаю, что GHC просто не может правильно определить типы для многомерных списков. Есть ли способ, которым я могу помочь, не прибегая к (Prelude.head . Prelude.head)?

1 ответ

Решение

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

head . head $ mlcons (mlcons 1 $ mlcons 2 $ toMinLenZero []) $ mlcons (mlcons 3 $ mlcons 4 $ toMinLenZero []) $ toMinLenZero [] :: Int
-- 1

(Функции, начинающиеся с ml все из модуля MinLen mono-traversable, который экспортируется classy-prelude)

Если вы просто хотите поведение Prelude.head функция, вы можете использовать unsafeHead снова из mono-traversable пакет и экспортируется по умолчанию:

unsafeHead . unsafeHead [[1,2],[3,4]]
-- 1

Существует также headMay в этом модуле, который можно использовать, если вы хотите по-разному обрабатывать ошибки, а не сбивать всю программу.

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