Создание экземпляра Applicative - PullRequest
5 голосов
/ 09 марта 2019

Все еще не сто процентов, как делать экземпляры более сложных типов.Имейте это:

data CouldBe a = Is a | Lost deriving (Show, Ord) 

Сделал экземпляр Functor, используя Maybe в качестве примера:

instance Functor CouldBe where 
  fmap f (Is x) = Is (f x) 
  fmap f Lost   = Lost 

Для выполнения чего-то вроде этого:

tupleCouldBe :: CouldBe a -> CouldBe b -> CouldBe (a,b)
tupleCouldBe x y = (,) <$> x <*> y

CouldBe должен быть экземпляром Applicative, но как бы вы поступили с этим?Конечно, я могу найти его и скопировать, но я хочу изучить процесс, стоящий за ним, и, наконец, получить декларацию CouldBe instance.

1 Ответ

3 голосов
/ 09 марта 2019

Вы просто записываете это, следуя типам:

instance Applicative CouldBe where
   {- 
        <b>Minimal complete definition:</b>
          pure, ((<*>) | liftA2)

      pure :: a -> f a 
      pure :: a -> CouldBe a

      liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
      liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c 
   -}
    pure a = fa
        where
        fa = ....

    liftA2 abc fa fb = fc
        where
        fc = ....

Согласно

data CouldBe a = Is a | Lost

наш набор инструментов

Is   :: a -> CouldBe a
Lost :: CouldBe a

, но мы также можем использоватьсопоставление с образцом, например

couldBe   is   lost  (Is a)    = is a
couldBe   is   lost  (Lost)    = lost
couldBe :: ? -> ? -> CouldBe a -> b
couldBe :: ? -> b -> CouldBe a -> b
couldBe :: (a -> b) -> b -> CouldBe a -> b

Итак,

    -- pure :: a -> f a 
    pure :: a -> CouldBe a     

совпадает с

    Is   :: a -> CouldBe a

, поэтому мы определяем

    pure a = Is a

Тогда,для liftA2 мы следуем случаям данных:

    -- liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
    -- liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c
    liftA2 abc Lost    _     = ...
    liftA2 abc  _     Lost   = ...
    liftA2 abc (Is a) (Is b) = fc
        where
        c = abc a b
        fc = ....     -- create an `f c` from `c`: 
                      -- do we have a `c -> CouldBe c` ?
                      -- do we have an `a -> CouldBe a` ? (it's the same type)

Но в первых двух случаях у нас нет a или b;поэтому мы должны придумать CouldBe c из ничего.У нас есть этот инструмент и в нашем наборе инструментов .

Завершив все пропущенные фрагменты, мы можем подставить выражения непосредственно в определения, исключив все ненужные промежуточные значения / переменные.

...