Невозможно реализовать складной экземпляр из-за неправильного типа

Я изучаю haskell и пытаюсь сделать красивую программу для печати. В какой-то момент я хочу получить длину строки (т.е. количество столбцов в этой строке). Чтобы иметь возможность сделать это с моим типом данных, я понимаю, что мне нужно реализовать Foldable, который опирается на Monoid.

Раньше моя строка была просто псевдонимом типа для списка, но ради обучения я хочу сделать этот шаг.

    import System.IO
    import System.Directory
    import Control.Monad
    import Data.Maybe
    import Data.Monoid
    import Data.Foldable
    import Data.Functor
    import Data.List.Split

    type Field = String
    data Row = Row [Field]

    instance Monoid Row where
        mempty = Row []


    instance Foldable Row where
        foldMap f (Row fs) = foldMap f fs

Но я получаю следующую ошибку компилятора (на ghci 8.0.2)

main.hs:20:19: error:
    • Expected kind ‘* -> *’, but ‘Row’ has kind ‘*’
    • In the first argument of ‘Foldable’, namely ‘Row’
      In the instance declaration for ‘Foldable Row’

Теперь я не знаком с тем, что такое тип данных. Я ожидал, что это просто отложится на единственное свойство Row типа List


person Hugo Peters    schedule 10.11.2019    source источник


Ответы (2)


Когда у нас есть Foldable T, T должен быть параметрическим типом, т. е. мы должны иметь возможность формировать типы T Int, T String и т. д.

В Haskell мы пишем T :: * -> * для "типа, параметризованного над типом", так как это напоминает функцию от типов к типам. Синтаксис * -> * называется видом T.

В вашем случае Row не параметризуется, это простой тип, что-то вроде *, а не * -> *. Итак, Foldable Row — это добрая ошибка. В некотором смысле складной объект должен быть универсальным контейнером, похожим на список, а не тем, который содержит только Field, как в вашем случае.

Вместо этого вы можете определить data Row a = Row [a] и использовать Row Field, когда вам нужен этот конкретный случай.

В качестве альтернативы вы можете попробовать MonoFoldable Row из пакета mono-traversable, но учтите, что это более продвинутый вариант, включающий семейства типов. Не относитесь к этому пути легкомысленно, пока не обдумаете его последствия. В конечном итоге все сводится к тому, зачем вам нужен экземпляр Foldable.

person chi    schedule 10.11.2019
comment
@HugoPeters Со стандартным length из Foldable и непараметризованным Row это действительно невозможно. Вы можете объявить другую функцию длины, но она должна иметь другое имя (или находиться в другом пакете и устранять неоднозначность между двумя функциями длины вручную). Например, MonoFoldable предоставляет olength, чтобы избежать конфликта имен. - person chi; 10.11.2019

каков тип типа данных?

Типы "типа *" — это типы вещей, которые могут появляться в программе на Haskell.

Пример: Int.

Не пример: Maybe.

a :: Int ; a = 1 может появиться в программе на Haskell, а b :: Maybe ; b = Just 1 — нет. Он должен быть b :: Maybe Int ; b = Just 1, чтобы он отображался в программе на Haskell.

Что такое Maybe Int? Это тип рода *, как и Int. Так что же такое Maybe? Это тип вида * -> *. Поскольку Maybe Maybe тоже недействителен.

Тип t, появляющийся после Maybe, сам должен быть типа *, чтобы Maybe t был типа *. Таким образом, вид Maybe есть * -> *.

Haskell now calls the kind * by new name, Type. Calling it Thing or something could have been more intuitive.

person Will Ness    schedule 11.11.2019