Реализация аппликативного функтора для пользовательского типа данных с двумя одинаковыми классами типов - PullRequest
0 голосов
/ 17 сентября 2018

Я пытаюсь сделать Twice членом аппликативного, но я получаю «Противоречивые определения для« a »» в реализации функтора: также я не уверен, как правильно реализовать <*>: /

data Twice a = Twice a a deriving (Show)

instance Functor Twice where
    fmap f (Twice a a) = Twice (f a) (f a)

instance Applicative Twice where
    pure x = (Twice x) x
    Twice f f <*> Twice x x = Twice ((f x) (f x))

Ответы [ 3 ]

0 голосов
/ 17 сентября 2018

Ошибки скорее синтаксические, чем семантические.В вашем определении:

Twice <b>f</b> <b>f</b> <*> Twice <b>x</b> <b>x</b> = Twice ((f x) (f x))

то же самое в определении Functor:

fmap f (Twice <b>a</b> <b>a</b>) = Twice (f a) (f a)

Вы пишете два f и два x в голове.Haskell не позволяет этого (Пролог делает, но даже тогда, вероятно, это не то, что вы имеете в виду).

Кроме того, в теле вы пишете:

((f x) (f x))

Это означает, что вы бы сделаливызов функции с f x функцией и f x аргументом, что опять же, вероятно, не то, что вы хотели.

Мы можем исправить это синтаксически следующим образом:

instance Functor Twice where
    fmap f (Twice a <b>b</b>) = Twice (f a) (f <b>b</b>)

instance Applicative Twice where
    pure x = Twice x x
    Twice <b>f</b> <b>g</b> <*> Twice <b>x</b> <b>y</b> = Twice <b>(f x) (g y)</b>

Обратите внимание, что вывсе еще необходимо доказать, что это действительный экземпляр Functor и Applicative, принимая во внимание ограничения, задокументированные для этих классов типов.

0 голосов
/ 17 сентября 2018

Путаница связана с использованием одного и того же имени для данных и типа;распространенная и принятая, даже рекомендуемая практика для всех, кроме самых начинающих хаскелеров.

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

data Twice a = MkTwice a a deriving (Show)         -- 'Mk' is for "make"

-- Twice a                         -- a type
-- MkTwice :: a -> a -> Twice a    -- data constructor

instance Functor Twice where
    -- fmap (f :: a -> b) :: Twice a -> Twice b
    fmap f (MkTwice x y) = MkTwice (f x) (f y)     -- transform both fields

instance Applicative Twice where
    pure x = MkTwice x x                 -- create two fields from one value
    MkTwice f g <*> MkTwice x y = MkTwice (f x) (g y)  -- combine both fields

Twice a - это тип с a переменная типа.

MkTwice - конструктор данных для этого типа.Он создает значения типа Twice a из двух значений типа a (скажем, x :: a и y :: a).Значения отображаются справа от = в определениях на Haskell (примерно).

Он также используется в шаблонах для значений типа Twice a.Образцы появляются слева от = в определениях на Haskell.В шаблонах Haskell может быть no дубликатов переменных шаблона.Каждая переменная шаблона обозначает некоторое значение.

Каждая переменная типа обозначает тип.

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

0 голосов
/ 17 сентября 2018

Вот проблемы и их исправления:

instance Functor Twice where
    -- fmap f (Twice a a) = Twice (f a) (f a)
    --               ^^^ you define `a` twice here. Replace this with:
    fmap f (Twice a b) = Twice (f a) (f b)

instance Applicative Twice where
    pure x = Twice x x -- You don't need brackets here so I removed them.
    -- Twice f f <*> Twice x x = Twice ((f x) (f x))
    -- ^^^^^^^^^     ^^^^^^^^^         ^^^^^^^^^^^^^
    -- You define f and x twice.
    -- You are also misusing brackets - this is not how to apply functions.
    -- A corrected version:
    Twice f1 f2 <*> Twice x1 x2 = Twice (f1 x1) (f2 x2)

Во-первых, если вы не дадите отдельным аргументам отдельные имена, это вызовет ошибку. Представьте, что я пишу f a a = a + 6, а затем прошу вас оценить f 1 2.

Во-вторых, вы неправильно понимаете, как применяются функции Haskell. Позвольте мне прояснить это: на большинстве языков вы пишете f(a,b,c), но на Хаскеле вы пишете f a b c. Если вы пишете f (a b c), это читается как f(a(b,c)).

...