Я изучаю Haskell, выполняя упражнение fp-course (https://github.com/system-f/fp-course)
При заполнении (*>)
в Application.hs
. Я не могу понять ответ следующим образом.
-- | Apply, discarding the value of the first argument.
-- Pronounced, right apply.
--
-- >>> (1 :. 2 :. 3 :. Nil) *> (4 :. 5 :. 6 :. Nil)
-- [4,5,6,4,5,6,4,5,6]
--
-- >>> (1 :. 2 :. Nil) *> (4 :. 5 :. 6 :. Nil)
-- [4,5,6,4,5,6]
--
-- >>> (1 :. 2 :. 3 :. Nil) *> (4 :. 5 :. Nil)
-- [4,5,4,5,4,5]
--
-- >>> Full 7 *> Full 8
-- Full 8
--
-- prop> \a b c x y z -> (a :. b :. c :. Nil) *> (x :. y :. z :. Nil) == (x :. y :. z :. x :. y :. z :. x :. y :. z :. Nil)
--
-- prop> \x y -> Full x *> Full y == Full y
(*>) ::
Applicative k =>
k a
-> k b
-> k b
(*>) ka kb = (pure id) <$> ka <*> kb
Например. k
это List
.
Тип (pure id)
будет List (a -> a)
Тип <$>
будет (a -> b) -> List a -> List b
Тип k a
будет List a
Почему <$>
первый тип параметра (a -> a)
может принимать (pure id)
какой тип List (a -> a)
Я не знаю, почему (pure id) <$> ka
может превратиться 1 :. 2 :. 3 :. Nil
в id :. id :. id :. Nil
Может ли кто-нибудь помочь? Спасибо!
Использование pure
используется только в контексте (->) a
экземпляра Applicative
. Действительно [src]:
instance Applicative ((->) r) where pure = const (<*>) f g x = f x (g x) liftA2 q f g x = q (f x) (g x)
Таким образом, это означает, что pure id
здесь эквивалентно const id
. Вместо этого, возможно, было бы лучше использовать const id
.
Причина, по которой он выберет (->) r
, только для области pure id
, что является важным аспектом, заключается в том, что fmap
(или <$>
), таким образом, нужна функция с левой стороны. Единственный способ добиться этого — позволить pure id
работать с instance Applicative (->) r
.
Но важно подчеркнуть, что экземпляр, который он выбирает для аппликации pure
, не имеет ничего общего с Applicative k
, который будет выбран для <$>
и <*>
.
Мы используем const id
, чтобы использовать return id
, независимо от элемента в списке, мы возвращаем id
. Таким образом, вероятно, было бы более ясно с:
(*>) :: Applicative k => k a -> k b -> k b
(*>) ka kb = const id <$> ka <*> kb
или проще:
(*>) :: Applicative k => k a -> k b -> k b
(*>) ka kb = (id <$ ka) <*> kb
Хотя обычно я не комментирую лишние скобки, это случай, который на 100% предназначен для работы так, как он работает. Все аппликационные операторы имеют инфиксный номер 4, а
<|>
— инфиксный номер 3. Это было специально выбрано для того, чтобы аппликативный/альтернативный синтаксический анализатор можно было писать без круглых скобок для операторов синтаксического анализа. Я думаю, что использование этих операторов без дополнительных скобок так же стоит запомнить, как и использование арифметики без дополнительных скобок.