Как Haskell оценивает эту функцию, определенную при частичном применении?
Я пытаюсь понять, как Haskell оценивает pp1 [1,2,3,4]
получить [(1,2),(2,3),(3,4)]
Вот:
1. xnull f [] = []
2. xnull f xs = f xs
3. (/:/) f g x = (f x) (g x)
4. pp1 = zip /:/ xnull tail
Я начинаю так:
a) pp1 [1,2,3,4] = (zip /:/ xnull tail) [1,2,3,4] -- (rule 4).
b) (zip /:/ xnull tail) [1,2,3,4]
= (zip (xnull [1,2,3,4]) (tail) [1,2,3,4]) -- (rule 3)
c) -- I'm not sure how to continue because xnull receives a function
-- and a param, and in this case it only receives a param.
Любая помощь?
3 ответа
Просто продолжайте расширяться:
pp1 [1, 2, 3, 4] = zip /:/ xnull tail $ [1, 2, 3, 4]
-- inline (/:/) f g x = f x (g x)
-- f = zip, g = xnull tail, x = [1, 2, 3, 4]
-- therefore:
= zip [1, 2, 3, 4] (xnull tail $ [1, 2, 3, 4])
-- inline the definition of xnull and note that the argument is not null
-- so we just want f x, or tail [1, 2, 3, 4]
= zip [1, 2, 3, 4] (tail [1, 2, 3, 4])
-- evaluate tail
= zip [1, 2, 3, 4] [2, 3, 4]
-- evaluate zip
= [(1, 2), (2, 3), (3, 4)]
Президентство оператора имеет значение. Вы не указали ассоциативность (/:/)
так что по умолчанию он был относительно слабым. Следовательно, (xnull tail)
связаны крепче, чем (/:/)
,
Кроме того, как примечание, (/:/)
уже существует в стандартной библиотеке как (<*>)
от Control.Applicative
, Это достаточно общее, так что это может быть трудно увидеть, но Applicative
экземпляр для Reader
(или, возможно, лучше понимать как функцию Applicative
) предоставляет именно этот пример. Это также известно как ap
от Control.Monad
,
zip <*> tail :: [b] -> [(b, b)]
zip <*> tail $ [1, 2, 3, 4] = [(1, 2), (2, 3), (3, 4)]
Это не верно
b) (zip /:/ xnull tail) [1,2,3,4] = (zip (xnull [1,2,3,4]) (tail) [1,2,3,4]) (rule 3)
потому что это должно быть
b) (zip /:/ xnull tail) [1,2,3,4] = (zip [1,2,3,4] (xnull tail [1,2,3,4])) (rule 3)
Ошибка заключается в чтении zip /:/ xnull tail
как в (zip /:/ xnull) tail
скорее, чем zip /:/ (xnull tail)
,
Я знаю, что это немного устарело. Но в любом случае, вот мое взятие..
Это помогает увидеть определение
pp1 = zip /:/ xnull tail
= (zip) /:/ (xnull tail)
= (/:/) zip (xnull tail)
Обратите внимание на круглые скобки вокруг (xnull tail)
с указанием приложения функции, имеющего более высокий приоритет инфиксных операторов.
Теперь определение (/:/)
это вернуть другую функцию q
это будет аргумент x
и вернуть результат применения функции, возвращенной частичным применением ее первого аргумента r
к тому, что возвращается от применения его второго аргумента s
,
То есть f
должно быть в состоянии принять по крайней мере 2 аргумента, в то время как g
нужно только взять хотя бы 1.
(/:/) f g = q
where
q x = r s
where
r = f x
s = g x
Обратите внимание, что r
является f x
, так q x
является f x s
,
Было бы понятнее написать
f /:/ g = (\x -> f x (g x))
Сейчас дано
pp1 = zip /:/ xnull tail
мы можем расширить до
pp1 = q
where
q x = r s
where
r = zip x
s = xnull tail x
или же
pp1 = (\x -> zip x $ xnull tail x)
Остальное просто заменяет x
с [1,2,3,4]
и делать оценки.