Вы просто записываете это, следуя типам:
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
из ничего.У нас есть этот инструмент и в нашем наборе инструментов .
Завершив все пропущенные фрагменты, мы можем подставить выражения непосредственно в определения, исключив все ненужные промежуточные значения / переменные.