【问题标题】:In Haskell, how do you use 'head' without creating a separate function?在 Haskell 中,如何在不创建单独函数的情况下使用“head”?
【发布时间】:2015-03-25 20:40:18
【问题描述】:

我对使用 Haskell 非常陌生,我不确定“head”是如何工作的。据我了解,它返回列表中的第一个元素。我一直在尝试使用它,但我不断收到错误。我通过创建一个单独的函数来找到头部添加了一个解决方法,但这似乎应该是不必要的。

我不明白为什么在这里调用 findHead:

single x = length (snd(x)) == 1

toList board
    | board == [] = []
    | otherwise = filter single board

findHead board = head (toList board)

这里不等同于调用toList:

single x = length (snd(x)) == 1

toList board
    | board == [] = []
    | otherwise =  head (filter single board)

在我看来,这两个应该是相同的,但只有第一个运行。为什么它们不被解释为相同?你能给我解释一下吗?在上面的代码中,'board' 是一个元组列表,每个元组的形式为 (x, [a,b,...])。

我在一些简单的事情中使用了“head”,例如:

union xs ys 
  | xs == [] = ys
  | ys == [] = xs
  | otherwise = union (tail xs)  (add (head xs) ys)

这似乎按我的预期工作。

【问题讨论】:

  • “但只有第一个运行” - 这是否意味着第二个挂起,或者它产生不同的输出,或者导致错误?
  • 在这两种情况下都需要调用head,即更改| board == [] = head []。然后我希望你能明白为什么 head 在这里是个坏主意。
  • 在绝大多数情况下,比起headtail 等部分投影,更喜欢(详尽!)模式匹配。
  • 顺便说一句,您不应该使用==[] 来检查空列表。这无缘无故地强加了Eq 约束,看起来很奇怪。您通常应该在这种上下文中使用模式匹配,而不是守卫。例如union [] ys = ysunion (x:xs) ys = union xs (x:ys)。如果你真的想要一个“它是空的”,你应该使用null。此外,询问列表的长度是否为 1 的效率可能远低于将其与 [x][_] 模式匹配的模式。
  • 另外,以后如果你用英文告诉我们代码应该做什么和它实际做什么,并给出一个实际的测试用例是非常有帮助的。否则,弄清楚如何解决它就像阅读茶叶。

标签: haskell head


【解决方案1】:

head部分。特别是,head [] 不会正常返回(引发异常)。这在 Haskell 中可能很难处理,这就是人们经常建议您避免使用偏函数的原因。

那么我们该怎么做呢?我们必须在类型中反映失败

safeHead :: [a] -> Maybe a
safeHead []     = Nothing
safeHead (a:as) = Just a

可以为tail做类似的功能

safeTail :: [a] -> Maybe [a]
safeTail []     = Nothing
safeTail (a:as) = Just as

【讨论】:

    【解决方案2】:

    我认为您需要退后一步,了解模式匹配、递归和单链表的工作原理。正如许多人所提到的,您正在编写的代码不会很好地工作。

    作为说明,我将如何在您的问题中编写各种函数:

    single :: (a, [b]) -> Bool    
    single (_, [_]) = True
    single _ = False
    
    toList :: [(a, [b])] -> [(a, [b])]
    toList board = filter single board
    
    findHead :: [(a, [b])] -> Maybe (a, [b])
    findHead [] = Nothing
    findHead board = head (toList board)
    
    -- This one actually does the same thing as the built-in `++` operator,
    -- but for the sake of illustration, I'll implement it.
    union :: [a] -> [a] -> [a]
    union [] ys = ys
    union (x:xs) ys = x : union xs ys
    

    【讨论】:

      猜你喜欢
      • 2022-12-28
      • 1970-01-01
      • 1970-01-01
      • 2013-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 2017-02-14
      相关资源
      最近更新 更多