【问题标题】:Haskell -- How should I avoid head or tail, and adopt pattern matching?Haskell - 我应该如何避免头部或尾部,并采用模式匹配?
【发布时间】:2018-04-25 16:06:19
【问题描述】:

我是 Haskell 的初学者,有人告诉我应该避免使用 head 和 tail 进行列表操作,而是使用模式匹配。我这里有一个代码sn-p,不知道应该怎么转换才能不使用head或tail?

myzipWith :: (a->b->c) -> [a] -> [b] ->[c]
myzipWith func [] [] = []
myzipWith func listA listB =
    [func (head listA) (head listB) ] ++ (myzipWith func (tail listA) (tail listB))

【问题讨论】:

  • myzipWith func (x:xs) (y:ys) = func x y : myzipWith func xs ys替换最后的等式。
  • 有充分的理由避免使用headtail。出于好奇,让我问一下:是你给的吗?
  • 了解headtail 的定义方式应该会有所帮助:head (x:_) = xtail (_:xs) = xs
  • @chepner 我知道定义,但我不太熟悉如何处理输入参数(我是否使用了正确的术语)以及函数签名。无论如何谢谢:)

标签: haskell


【解决方案1】:
myzipWith :: (a->b->c) -> [a] -> [b] ->[c]
myzipWith func [] [] = []
myzipWith func (headA:restA) (headB:restB) =
    [func headA headB] ++ myzipWith func restA restB

但请注意,附加 (++) 不是必需的。这会更惯用(也更有效):

    func headA headB : myzipWith func restA restB

【讨论】:

  • 另请注意,模式匹配并非详尽无遗,打开警告应指出。
  • 为了优雅地处理所有(三个)边缘情况,最好删除定义的第一行并在另一行之后添加myzipWith _ _ _ = [] - “给定任何不匹配的列表,返回[]"。
  • 虽然您的建议更惯用,但效率并不高,事实上我怀疑它会生成完全相同的代码,因为 ++ 将被内联。
  • @luqui,可能会进行优化,但是为了优化而对列表文字进行脱糖处理是很棘手的。当我不需要的时候,我真的不想依赖它。
  • 大家好,感谢 cmets,这很有帮助,我对这个主题有了更多的了解 :) 干杯 :)
【解决方案2】:
myzipWith func (a:as) (b:bs) = [func a b] ++ (myzipWith func as bs)

语法function (x:xs) 将传递给function 的列表分成两部分:第一个元素x 和列表的其余部分xs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    相关资源
    最近更新 更多