Haskell中列表中的模式匹配元素

wmtdaxz3  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(172)

假设我有以下类型,其中KType在其他地方定义:

data PExpr = 
    PVal KType |
    PCall String [PExpr]

我有一个功能:

tryReplace:: PExpr -> Maybe PExpr

对于我们的目的,它执行以下操作:
1.如果给定的PExpr是PVal,则返回Nothing
1.如果给定的PExpr是PCall并且为空,则返回Nothing
1.如果给定的PExpr是PCall并且完全由PVal组成,则返回Nothing
1.如果给定的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。
我确信有一个函数做的事情与已经定义的非常相似,但不管怎样,我正在尝试实现我自己的版本。
除非有一个模式函数match case可以处理#3,否则我想不出让#4工作的方法,因为我认为在遍历给定的列表时,我将被迫构建一个列表。但是,如果找到一个PCall,构建的列表甚至可能不会返回,这意味着额外的工作是白做的。我应该如何着手呢?我应该定义另一个函数来帮助实现#4吗?

brqmpdu1

brqmpdu11#

您可以使用一个附加函数来确定列表是否满足#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

Just [PExpr]可以代替(Bool, [PExpr])实现为hasPCall,但那会比这个更混乱。

lnlaulya

lnlaulya2#

让我们简化一下。假设您有一个项目列表,可以是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 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])

相关问题