[英]Pattern Matching Element in List in Haskell
假設我有以下類型,其中 KType 在其他地方定義:
data PExpr =
PVal KType |
PCall String [PExpr]
我有一個功能:
tryReplace:: PExpr -> Maybe PExpr
出於我們的目的,執行以下操作:
到目前為止,這就是我完成 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]
,但這會比這個更混亂。
讓我們簡化。 假設您有一個項目列表,可以是A
、 B
、 C
之一:
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.