Первоклассная прелюдия (зав. Головой)
Я пытаюсь преобразовать несколько проектов в 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
в этом модуле, который можно использовать, если вы хотите по-разному обрабатывать ошибки, а не сбивать всю программу.