新的haskell(或一般的函数式编程语言),所以我仍然很难将我脑海中的逻辑转换为实际的代码。
鉴于以下内容
data User = User String deriving (Eq, Show)
data Task = Task String deriving (Eq, Show)
data Command =
Add User
| Create Task
| Allow (User, Task)
deriving (Eq, Show)
我想确保每个Allow都有一个已添加的用户。上述逻辑将在函数Verified :: [Command] - >中定义。布尔
example = [
Add (User "Michael"),
Create (Task "Laundry"),
Allow (User "Michael", Task "Laundry")
]
Verified example -- Return True
example2 = [
Add (User "Michael"),
Create (Task "Laundry"),
Allow (User "Bob", Task "Laundry")
]
Verified example2 -- Return False
以下是我的思考过程,如果你能帮助我将其翻译成代码/改进我的想法,我会非常感激
反转命令列表。如果我看到一个允许用户和任务,那么在列表的某个地方必须是真的,有一个添加与该特定用户。否则,返回false。
在Prelude中使用elem来查看命令中是否存在这样的Add(我在考虑递归)。
现在我只能成功创建一个反转列表的简单函数,
reverseList :: [Command] -> [Command]
reverseList [] = []
reverseList (x:xs) = (reverse xs) ++ [x]
但除此之外,我真的不知道从哪里开始实施Verified :: [Command] - >布尔
编辑:刚发现Haskell有一个内置的反向函数,猜测我的reverseList将不再使用了
答案 0 :(得分:1)
我的理解是命令列表表示依赖于每个先前命令有效或无效的序列。也就是说,[Add "Bob", Allow "Bob" ...]
有效,而[Allow "Bob" ..., Add "Bob"]
。
在这种情况下,执行此操作的最简单方法可能是反转列表并迭代它;如果找到Allow
,请将其插入您必须找到的Add
集合中;如果您找到Add
,请将其从必须找到的Add
集中删除。然后,一旦到达空列表,如果您的集合不为空,您就会发现命令序列无效。
您可以使用列表来表示集合,但使用Data.Set.Set
会更容易,import qualified Data.Set as S
verify :: [Command] -> Bool
verify = go S.empty . reverse where
go :: S.Set User -> [Command] -> Bool
go s [] = error "TODO"
go s (x:xs) = case x of
Create {} -> go s xs
Add u -> error "TODO"
Allow (u, _) -> error "TODO"
已经定义了插入和删除(称为删除)函数。
以下是一些可以帮助您入门的代码:
Ord
你可以使用折叠,但使用原始递归编写它可能很有启发性。
要实现此目的,您还需要为User
派生 newtype User = User String deriving (Eq, Show, Ord)
:
Scroll right > go :: S.Set User -> [Command] -> Bool
go s [] = S.null s
go s (x:xs) = case x of
Create {} -> go s xs
Add u -> go (S.delete u s) xs
Allow (u, _) -> go (S.insert u s) xs
解决方案(ps给我剧透标签堆栈溢出):
{{1}}
答案 1 :(得分:1)
这个怎么样:
首先从reverse
导入Data.List
:
import Data.List (reverse)
定义verify
以在命令列表的反面应用verifyBackwards
:
verify :: [Command] -> Bool
verify cmds = verifyBackwards (reverse cmds)
verifyBackwards
然后会为每个元素调用verifyElem
以及反向命令列表的其余部分(即原始列表中该元素之前的元素)and
将结果与递归调用verifyBackwards
以验证其余元素:
verifyBackwards :: [Command] -> Bool
verifyBackwards [] = True
verifyBackwards (x:xs) = verifyElem x xs && verifyBackwards xs
最后verifyElem
将为除True
命令之外的所有命令返回Allow
。对于Allow
命令,它会在Add
编辑之前检查用户是否为Allow
:
verifyElem :: Command -> [Command] -> Bool
verifyElem (Allow (User u, _)) xs = elem (Add (User u)) xs
verifyElem _ _ = True