簡體   English   中英

Haskell列表中的模式匹配元素

[英]Pattern Matching Element in List in Haskell

假設我有以下類型,其中 KType 在其他地方定義:

data PExpr = 
    PVal KType |
    PCall String [PExpr]

我有一個功能:

tryReplace:: PExpr -> Maybe PExpr 

出於我們的目的,執行以下操作:

  1. 如果給定的 PExpr 是 PVal,則返回 Nothing
  2. 如果給定的 PExpr 是 PCall 並且為空,則返回 Nothing
  3. 如果給定的 PExpr 是 PCall 並且完全由 PVal 組成,則返回 Nothing
  4. 如果給定的 PExpr 是一個 PExpr 並且在列表中有一個 PCall,則返回 (Just PExpr),其中在列表中找到的第一個 PCall 被替換為全局定義的 KType x。

到目前為止,這就是我完成 1 和 2 的方式:

tryReplace (PVal _) = Nothing
tryReplace (PCall _ []) = Nothing

當 #4 實施時,我不太確定我的 #3 版本是否會保留:

tryReplace (PCall _ [PVal _]) = Nothing
tryReplace (PCall str (PVal x:xs)) = tryReplace (PCall str xs)

我本質上希望 #4 像這樣進行模式匹配:

tryReplace (PCall str (PVal a:PVal b:...:PCall _:rest)) = 
    Just (PCall str (PVal a:PVal b:...:PVal newValue:rest))

"..." 應該代表在找到 PCall 之前的所有 PVal。

我確信有一個功能與已經定義的非常相似,但無論如何我都在嘗試實現我自己的版本。

除非有一個可以處理 #3 的模式函數匹配案例,否則我想不出 #4 的工作方式,因為我認為我將在遍歷給定列表時被迫構建一個列表。 但是,如果找到 PCall,甚至可能不會返回正在構建的列表,這意味着額外的工作是白做的。 我該怎么辦? 我應該定義另一個函數來幫助實現#4嗎?

您可以使用附加函數來確定列表是否滿足 #3 或 #4,並相應地返回替代列表

hasPCall :: [PExpr] -> (Bool, [PExpr])
hasPCall [] = (False, [])
hasPCall (PCall _ _ : rst) = (True, (PVal newValue:rst))
hasPCall (PVal a : rst) = (fst val, (PVal a:snd val))
    where
        val = hasPCall rst

tryReplace:: PExpr -> Maybe PExpr
tryReplace (PVal _) = Nothing
tryReplace (PCall _ []) = Nothing
tryReplace (PCall s n) = case val of
    (True, a) -> Just (PCall s (snd newlist))
    (False, _) -> Nothing
  where
    newlist = hasPCall n

代替(Bool, [PExpr]) ,可以為hasPCall實現Just [PExpr] ,但這會比這個更混亂。

讓我們簡化。 假設您有一個項目列表,可以是ABC之一:

data Item = A | B | C
  deriving (Show)

xs1 = []
xs2 = [A, B, B, A, A]
xs3 = [A, A, A, A, A]
xs4 = [B, B, B, A, B]
xs5 = [A, A, A, A, B]

我們可以添加一個布爾值來記住到目前為止我們只見過A

import Control.Arrow

process :: (Bool, [Item]) -> (Bool, [Item])
process (_, []) = (True, [])
process (_, A:xs) = second (A :) (process (True, xs))
process (_, B:xs) = (False, C : xs)

這里我們使用second @(->) :: (b -> c) -> (d, b) -> (d, c)在結果元組的第二部分添加一個A

ghci> :set -XTypeApplicationsghci>
:t second @(->)
second @(->) :: (b -> c) -> (d, b) -> (d, c)
ghci> second (A:) (True, [B, C])
(True,[A,B,C])

這會給我們:

ghci> process (True, xs1)
(True,[])
ghci> process (True, xs2) 
(False,[A,C,B,A,A])
ghci> process (True, xs3)
(True,[A,A,A,A,A])
ghci> process (True, xs4)
(False,[C,B,B,A,B])
ghci> process (True, xs5)
(False,[A,A,A,A,C])

state monad的幫助下,我們甚至可以隱藏輸入Bool並獲得:

process' :: State [Item] Bool
process' = state go
  where
    go [] = (True, [])
    go (A:xs) = second (A:) (go xs)
    go (B:xs) = (False, C:xs)

給出相同的結果:

ghci> runState process' xs1
(True,[])
ghci> runState process' xs2
(False,[A,C,B,A,A])
ghci> runState process' xs3
(True,[A,A,A,A,A])
ghci> runState process' xs4
(False,[C,B,B,A,B])
ghci> runState process' xs5
(False,[A,A,A,A,C])

暫無
暫無

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

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