假設我有以下型別,其中 KType 在其他地方定義:
data PExpr =
PVal KType |
PCall String [PExpr]
我有一個功能:
tryReplace:: PExpr -> Maybe PExpr
出于我們的目的,執行以下操作:
- 如果給定的 PExpr 是 PVal,則回傳 Nothing
- 如果給定的 PExpr 是 PCall 并且為空,則回傳 Nothing
- 如果給定的 PExpr 是 PCall 并且完全由 PVal 組成,則回傳 Nothing
- 如果給定的 PExpr 是 PCall 并且在串列中有 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嗎?
uj5u.com熱心網友回復:
您可以使用附加函式來確定串列是否滿足 #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])
,Just [PExpr]
可以實作,hasPCall
但這會比這個更混亂。
uj5u.com熱心網友回復:
讓我們簡化。假設您有一個專案串列,可以是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
我們可以添加一個布林值來記住到目前為止我們只見過s:
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])
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/495988.html
上一篇:`NS`型別的大小寫匹配