[英]applicative functor: <*> and partial application, how it works
[英]how to print intermediate result in Functor and Applicative in Haskell
我正在閱讀 Graham Hutton 的《Haskell 2nd 編程》一書。 https://www.cs.nott.ac.uk/~pszgmh/pih.html#slides
說到第 13.4 章排序解析器,它包含以下功能:
> parse three "abcdef"
[((’a’,’c’),"def")]
> parse three "ab"
[]
我想了解在幕后評估它們的中間步驟是什么。 您可以在此處找到用於解析器的 Functor 和 Applicative 的工作源代碼:
import Control.Applicative
import Data.Char
-- Basic definitions
newtype Parser a =
P (String -> [(a, String)])
parse (P p) inp = p inp
item :: Parser Char
item = P (\inp -> case inp of
[] -> []
(x:xs) -> [(x, xs)])
-- Sequencing parsers
instance Functor Parser
-- fmap :: (a -> b) -> Parser a -> Parser b
where
fmap g p =
P
(\inp ->
case parse p inp of
[] -> []
[(v, out)] -> [(g v, out)])
--parse (fmap toUpper item) "abc"
instance Applicative Parser
-- pure :: a -> Parser a
where
pure v = P (\inp -> [(v, inp)])
-- <*> :: Parser (a -> b) -> Parser a -> Parser b
pg <*> px =
P
(\inp ->
case parse pg inp of
[] -> []
[(g, out)] -> parse (fmap g px) out)
three :: Parser (Char, Char)
three = pure g <*> item <*> item <*> item
where
g x y z = (x, z)
我已經嘗試通過以下方式替換 Functor 和 Applicative 的定義,但不知道如何進一步做:
parse three "abc"
three :: Parser (Char,Char)
three
= pure g <*> item <*> item <*> item
=P (\inp -> [(g,inp)]) <*> item <*> item <*> item (apply pure v)
-----------------------------------------------------------------------------------------------------------
=P (
\inp -> case parse P (\inp -> [(g,inp)]) inp of (apply pg <*> px)
[] -> []
[(g,out)] -> parse (fmap g item) out
)
<*> item <*> item
-----------------------------------------------------------------------------------------------------------
=P (
\inp -> case (\inp -> [(g,inp)]) inp of (apply parse (P p) inp = p inp
[] -> []
[(g,out)] -> parse (fmap g item) out
)
<*> item <*> item
-----------------------------------------------------------------------------------------------------------
Here, inp=”abc”, (\inp -> [(g,inp)]), inp = [ (f x y z =(x,z), “abc” )]
=P (
parse (
fmap g item
) out
) (apply \inp -> [(g,inp)] on inp)
<*> item <*> item
這是一個好的開始。 您的最后一步看起來不太正確。 剝離共享部分,你已經寫了
\inp -> case (\inp -> [(g,inp)]) inp of [] -> []; [(g, out)] -> parse (fmap g item) out
=
parse (fmap g item) out
這個等式對我來說看起來不太正確:前者是 function,而后者不是。 此外,后者指的是自由變量out
,而前者不是(因為out
受它所包含的模式匹配的約束)。 更仔細的延續看起來像這樣:
\inp -> case (\inp -> [(g,inp)]) inp of [] -> []; [(g, out)] -> parse (fmap g item) out
= { beta reduction, substituting inp for inp }
\inp -> case [(g, inp)] of [] -> []; [(g, out)] -> parse (fmap g item) out
= { case reduction, substituting g for g and inp for out }
\inp -> parse (fmap g item) inp
如果你願意,你可以 eta-reduce 來parse (fmap g item)
。 將其重新插入我們在上面放置的共享部分,我們有:
three
=
P (parse (fmap g item)) <*> item <*> item
結果可以在ghci中驗證:
*Parsing> parse three "abc"
[(('a','c'),"")]
*Parsing> let g x y z = (x,z)
*Parsing> parse (P (parse (fmap g item)) <*> item <*> item) "abc"
[(('a','c'),"")]
作為下一步,您可以在三個地方進行下一次定義擴展以實現進一步的進展:
fmap g item
中展開fmap
。P (...) <*> item
中的內部(<*>)
。(P (...) <*> item) <*> item
中擴展外部(<*>)
。祝你好運!
(這是對“根據@Daniel Wagner 的建議,我在fmap gp
上進行擴展:”更新的回應)
最后一個替換是否正確?
無法回答,因為之前的步驟不正確。
你的展開有幾個問題,說明你寫的馬虎,導致了錯誤。 也可能存在概念問題。
例如,當您將three = P...
內聯到parse three "abc"
時,您沒有在P...
周圍加上括號,導致這一行:
parse P (parse (P...)) <*> item <*> item "abc"
這很可能在語法上不正確,因為它會被解析為
(parse P (parse (P ...))) <*> item <*> (item "abc")
雖然您可能的意思是:
parse ((P ...) <*> item <*> item) "abc"
如果您認為,我這樣做只是為了使事情更容易編寫,然后檢查一下:此語法錯誤還導致您錯誤地處理獨立於<*> item <*> item "abc"
的parse P (parse (P...))
部分<*> item <*> item "abc"
,這是一個嚴重的錯誤,並使之后的大部分內容都變得無關緊要。
另一件事是這樣的:
Here, inp="abc", (\inp -> [(g,inp)]), inp = [ (fxyz =(x,z), "abc" )]
這條線根本沒有意義。 由於您只是擴展three
,因此說inp
是任何東西都是無效的。 考慮(\x -> x)
。 這里的x
只是為了建立結果與參數相同的關系,而不是任何特定的值。 這就是它是一個綁定變量的意思。
(當你說(\inp -> [(g,inp)]), inp = [ (fxyz =(x,z), "abc" )]
時,我什至不知道你在說什么。也許你能澄清一下嗎?)
這也意味着以下沒有意義
(\inp -> case parse item inp of [] -> []; [(v, out)] -> [(gv, out)]))<*> item <*> item “abc” ={substitute inp for "abc"} case parse item "abc" of [] -> []; [(v, out)] -> [(gv, out)]<*> item <*> item
這里有多個問題。 首先,第一行有一個額外的近括號,這使得很難理解你的意思。 如果我們忽略這一點,那么在你有(\inp ->) <*> item...
之前,但之后你沒有在case
表達式周圍加上括號,從而制作<*>
。
此外,您似乎想在此處進行 beta-reduction。 Beta 縮減始終具有(\v -> E) a
形式,其中 lambda 直接應用於參數。 你不能隨便說 ' v
等於a
' 並在表達式中跳來跳去。
例如,如果我們有f (\x -> x + 1) 3
,將其簡化為f 4
是否正確? 不,因為 lambda 未應用於3
。
這意味着即使前半部分是正確的,你寫的后半部分也是基於一個無意義的步驟,是無關緊要的。
我非常想告訴你如何修復你的減少,但我很遺憾地說我認為你寫的東西現在已經無法修復了。 如果你想有一個正確的歸約軌跡,請更加小心每一步的語法和有效性,並從頭開始重新做所有事情。
作為輔助,您應該檢查幾件事以查看是否出現問題:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.