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

发布于 2025-02-10 04:24:11 字数 1077 浏览 2 评论 0原文

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

data PExpr = 
    PVal KType |
    PCall String [PExpr]

我有一个功能:

tryReplace:: PExpr -> Maybe PExpr 

出于我们的目的,请执行以下操作:

  1. 如果给定的PEXPR是PVAL,则无需返回
  2. ,如果给定的PEXPR是PCALL,并且是空的,并且是空的
  3. 如果给定的PEXPR是PCALL,则一无所获,并且完全由PVAL
  4. 返回(仅PEXPR)组成,如果给定的PEXPR是PCALL,并且在列表中具有PCALL,则列表中发现的第一个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吗?

Let's say I have the following type, where KType is defined somewhere else:

data PExpr = 
    PVal KType |
    PCall String [PExpr]

I have a function:

tryReplace:: PExpr -> Maybe PExpr 

That for our purposes, does the following:

  1. Returns Nothing if the given PExpr is a PVal
  2. Returns Nothing if the given PExpr is a PCall and is empty
  3. Returns Nothing if the given PExpr is a PCall and is composed entirely of PVal
  4. Returns (Just PExpr) if the given PExpr is a PCall and has a PCall in the list, where the first PCall found in the list is replaced with a globally defined KType x.

So far, this is what I have in the way of accomplishing 1 and 2:

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

I am less sure about my version of #3 staying when #4 is implemented:

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

I essentially want #4 to pattern match as such:

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

"..." is supposed to represent all the PVal before a PCall is found.

I'm sure there's a function that does something very similar to this already defined, but regardless of that I am trying to implement my own version.

Unless there is a single pattern function match case that can take care of #3, I can't think of a way for #4 to work, as I think I would be forced to build a list while traversing the given list. But the list being built might not even be returned if a PCall is found, which means extra work was done for nothing. How should I go about this? Should I define another function to assist in implementing #4?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初相遇 2025-02-17 04:24:11

您可以使用一个附加功能,该功能将找出列表是否满足#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]),只是[PEXPR]可以为haspcall实现,但这比这更凌乱。

You can use an additional function that will find out if the list satisfies #3 or #4, and returns a substitute list accordingly

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

Instead of (Bool, [PExpr]), Just [PExpr] can be implemented for hasPCall but that would be messier than this one.

笑脸一如从前 2025-02-17 04:24:11

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

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])

Lets simplify. Assume you have a list of items which can be one of 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]

We can add a Boolean to remember that we have only seen As so far:

import Control.Arrow

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

Here we are using second @(->) :: (b -> c) -> (d, b) -> (d, c) to add an A in the second part of the result tuple:

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

Which will give us:

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])

With the help of the state monad we can even hide the input Bool and get:

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

Giving the same result:

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])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文