假设我有以下类型,其中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吗?
2条答案
按热度按时间brqmpdu11#
您可以使用一个附加函数来确定列表是否满足#3或#4,并相应地返回一个替代列表
Just [PExpr]
可以代替(Bool, [PExpr])
实现为hasPCall
,但那会比这个更混乱。lnlaulya2#
让我们简化一下。假设您有一个项目列表,可以是
A
、B
、C
中的一个:我们可以添加一个布尔值来记住我们目前只看到了
A
s:这里我们使用
second @(->) :: (b -> c) -> (d, b) -> (d, c)
在结果元组的第二部分添加一个A
:这将为我们提供:
在state monad的帮助下,我们甚至可以隐藏输入
Bool
并得到:给出相同结果的: