簡體   English   中英

如何在 Haskell 中的 Functor 和 Applicative 中打印中間結果

[英]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'),"")]

作為下一步,您可以在三個地方進行下一次定義擴展以實現進一步的進展:

  1. 您可以在fmap g item中展開fmap
  2. 您可以擴展P (...) <*> item中的內部(<*>)
  3. 您可以在(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

這意味着即使前半部分是正確的,你寫的后半部分也是基於一個無意義的步驟,是無關緊要的。


我非常想告訴你如何修復你的減少,但我很遺憾地說我認為你寫的東西現在已經無法修復了。 如果你想有一個正確的歸約軌跡,請更加小心每一步的語法和有效性,並從頭開始重新做所有事情。

作為輔助,您應該檢查幾件事以查看是否出現問題:

  1. 每個步驟都應該在語法上有效。 沒有未綁定的變量,沒有丟失的括號等。
  2. 如果原始表達式類型檢查,那么每個步驟也必須進行類型檢查並且具有相同的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM