【问题标题】:Haskell - Comparing different items with one another within a listHaskell - 将列表中的不同项目相互比较
【发布时间】:2014-11-23 21:38:59
【问题描述】:

刚接触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)

我想确保每个允许都有一个已添加的用户。上述逻辑将定义在一个函数 Verified :: [Command] -> Bool

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

以下是我的思考过程,如果您能帮我将其转化为代码/完善我的想法,我将不胜感激

  1. 反转命令列表。如果我看到带有用户和任务的允许,那么在列表下方的某处肯定有该特定用户的添加。否则,返回 false。

  2. 在 Prelude 中使用 elem 来查看命令中是否存在这样的 Add(我正在考虑递归)。

目前我只能成功创建一个反转列表的简单函数,

reverseList :: [Command] -> [Command]
reverseList [] = []
reverseList (x:xs) = (reverse xs) ++ [x]

但除此之外,我真的不知道从哪里开始实施已验证 :: [Command] -> Bool

编辑:刚发现Haskell内置了reverse功能,估计我的reverseList不会再用了

【问题讨论】:

  • 请注意,reverseList (x:xs) = (reverse xs) ++ [x] 是一个非常糟糕的主意(n^2 复杂度)。
  • 是的,有趣的是,我刚刚阅读了一篇关于如何实现反向功能的糟糕方法的文章。不过我将使用内置的反向功能!

标签: haskell recursion


【解决方案1】:

我的理解是命令列表代表一个序列,该序列取决于每个先前的命令是有效还是无效。即[Add "Bob", Allow "Bob" ...] 有效,而[Allow "Bob" ..., Add "Bob"]

在这种情况下,最简单的方法可能是反转列表并遍历它;如果您找到Allow,将其插入您必须找到的Adds 集合中;如果您找到Add,请将其从您必须找到的Adds 集中删除。然后,一旦你到达空列表,如果你的集合不为空,你就会发现命令序列是无效的。

您可以使用列表来表示集合,但使用 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"

您可以使用折叠,但使用原始递归编写它可能很有启发性。

为此,您还需要为User 派生Ord

 newtype User = User String deriving (Eq, Show, Ord)

解决方案(ps给我剧透标签堆栈溢出):

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 

【讨论】:

  • 奇怪,我可以做一个扰流板代码块,它在编辑时可以正确预览,但是在我的浏览器的隐身窗口中检查显示,在编辑后扰流板标签似乎不起作用制作。我可能会将此报告为 meta 上的错误。
【解决方案2】:

这个怎么样:

首先从Data.List导入reverse

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 将为除Allow 命令之外的所有命令返回True。对于Allow 命令,它会检查用户在被Allowed 之前是Added:

verifyElem :: Command -> [Command] -> Bool
verifyElem (Allow (User u, _)) xs = elem (Add (User u)) xs
verifyElem _ _ = True

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多