Переопределение экземпляра класса типов

  1. Я пытаюсь ответить на этот вопрос: «Учитывая алгебраический тип данных

    data Maybe a = Nothing | Just a
    

    выберите правильное объявление экземпляра, которое показывает, что конструктор типа Maybe является Monad.» (взято отсюда: «DelftX: FP101x Introduction to Functional Programming».

  2. То, как я пытаюсь ответить на это, состоит в том, чтобы составить каждый потенциальный ответ по очереди, например, этот:

    instance Monad Maybe where
               return x = Just x
               Nothing >>= _ = Nothing
               (Just x ) >>= f = f x
    
  3. Я не могу его скомпилировать, потому что он уже определен в прелюдии.

    HwEx9.hs:16:10: error:
        Duplicate instance declarations:
          instance Monad Maybe -- Defined at HwEx9.hs:16:10
          instance Monad Maybe -- Defined in `GHC.Base'
    

Мой вопрос: как я могу его скомпилировать?


person Atir    schedule 31.08.2017    source источник
comment
Самый простой способ: определить свой собственный Maybe-подобный тип.   -  person melpomene    schedule 31.08.2017
comment
Невозможно избежать импорта экземпляра класса типов для данного типа. (см. далее stackoverflow.com/a/8731340/6476589)   -  person Brendan Murphy    schedule 01.09.2017
comment
Изменить его на MyMaybe?   -  person user253751    schedule 01.09.2017


Ответы (1)


Я бы просто имитировал тип данных Maybe, например:

data Maybe' a = Just' a | Nothing' deriving Show

instance Monad Maybe' where
    return x = Just' x
    Nothing' >>= _ = Nothing'
    (Just' x) >>= f = f x

В последних версиях ghc это не удастся, так как последние версии требуют, чтобы вы также реализовали аппликатив. Мы можем сделать это так:

instance Applicative Maybe' where
    pure = Just'
    (Just' f) <*> (Just' x) = Just' (f x)
    _ <*> _ = Nothing'

Applicative требует, чтобы тип был экземпляром Functor, поэтому мы можем реализовать его следующим образом:

instance Functor Maybe' where
    fmap f (Just' x) = Just' (f x)
    fmap _ Nothing' = Nothing'

Затем он будет скомпилирован. Преимущество этого подхода еще и в том, что мы можем легко сравнить две монады Maybe, например:

*Main> Just 2 >>= (\x -> Just (x+1))
Just 3
*Main> Just' 2 >>= (\x -> Just' (x+1))
Just' 3
person Willem Van Onsem    schedule 31.08.2017
comment
Следуя вашему совету (спасибо), как бы вы имитировали список Monad, заданный следующим образом: instance Monad [] где return x = [x] xs ››= f = concat (map f xs) - person Atir; 03.09.2017
comment
Не должно быть: data List' a = Empty' | Минусы (Список а) (Спасибо за быстрый ответ). - person Atir; 03.09.2017
comment
Это не работает: вот код (взято отсюда: schoolofhaskell.com/school/starting-with-haskell/) data List a = Nil | Cons a (List a) instance (Show a) => Show (List a), где show Nil = show (Cons x xs) = show x ++, ++ show xs instance Список функторов, где fmap f Nil = Nil fmap f ( Cons x xs) = Cons (fx) (fmap f xs) instance Applicative List, где pure = Cons x Nil (List f) ‹*› (List x) = List (fx) _ ‹*› _ = Nil (ошибки: не в области: конструктор данных `List') - person Atir; 03.09.2017
comment
Это не работает: вот код (взято отсюда: schoolofhaskell.com/school/starting-with-haskell/) data List a = Nil | Cons a (List a) instance (Show a) => Show (List a), где show Nil = show (Cons x xs) = show x ++ , ++ show xs instance Список функторов, где fmap f Nil = Nil fmap f ( Cons x xs) = Cons (fx) (fmap f xs) instance Applicative List, где pure = Cons x Nil (List f) ‹*› (List x) = List (fx) _ ‹*› _ = Nil (ошибки: не в области: конструктор данных `List') - person Atir; 03.09.2017