【问题标题】:Non-exhaustive patterns, Haskell非穷举模式,Haskell
【发布时间】:2018-03-24 07:11:25
【问题描述】:

我正在尝试编写函数 tails,它通过以下方式将字符串转换为字符串列表:

tails "abc" = ["abc", "bc", "c", ""]

这是我的实现:

tails :: [Char] -> [[Char]]
tails (x:xs)
  | length (x:xs) == 0 = [""]
  | otherwise = (x:xs) : tails xs

正如标题所示,此函数中存在非详尽的模式。不幸的是,我不明白这是怎么回事。

我是 Haskell 的新手...任何帮助将不胜感激!

【问题讨论】:

  • (x:xs) 假定列表不为空。
  • 使用-Wall 开启警告会发现问题。

标签: haskell functional-programming non-exhaustive-patterns


【解决方案1】:

该模式并不详尽,因为它不能接受[]。列表的形式为[]a:as,其中a 是前导元素,as 是尾随元素的列表。因此,模式x:xs 仅在列表具有前导元素时才匹配。修复:

tails :: [Char] -> [[Char]]
tails xs
    | length xs == 0 = [""]
    | otherwise = let (_:xs') = xs in xs : tails xs'

然后xs 接受列表,无论其形式如何。 但是由于length,这是低效的,并且不适用于无限列表。

这应该完全有效,它直接进行模式数学:

tails :: [Char] -> [[Char]]
tails [] = [""]
tails xs@(_:xs') = xs : tails xs'

【讨论】:

  • 我明白了!感谢您的解释!但是,我认为您的代码不像递归情况那样工作,tails 采用相同的参数。但这可以通过使用模式匹配的情况轻松解决。
  • 啊,对不起。固定。
  • 我还添加了一个更简单的版本。
  • 应该删除给定的第一个版本。当您只需要查看最顶部时,计算length xs == 0 将运行整个列表,并且也不适用于无限列表。它也是单调的。第二个版本是正确的。
  • @HTNW 已修复。谢谢。
【解决方案2】:

试试这个怎么样,或者至少从中得到一些逻辑。它运作良好。 它有一个辅助函数来将字符串转换成一个单独的字符列表,例如“abc”变成[“a”、“b”、“c”]。像这样处理它们并不那么复杂,并且有必要在结果列表中收集不同的字符串。函数集中有两个函数,第三个函数保证用一个参数调用主函数。主要功能在一条线上,但使用警卫。

ca = [[c] | c <- "abcdef"]
f (l1,ls) | null ls = l1++[[]] | True = f ( l1 ++ [concat ls], (tail ls))
f ([],ca)
["abcdef","bcdef","cdef","def","ef","f",""]

2018 年 4 月 4 日编辑 我错了。列表参数不必事先制作成列表。如果不这样做,通过删除 concat 函数并将参数列表从元组更改为单个删除的批次或括号,函数会变得更简单。

fs l1 ls = if null ls then l1++[""] else fs (l1++[ls]) (tail ls)

它的调用方式也不同。

fs []“你好!”

这本身就产生了正确的结果。

编辑/添加 2018 年 4 月 11 日

当 Haskell 使用 (x:xs) 将输入拆分为头部和尾部时,不断重复出现(没有双关语)的是对 tail 的依赖,它们已准备好使用。这是一个基本的递归函数,它仅将(x:xs) 用于头部和尾部。我生成输入列表的所有尾部,包括 null。

t [] = [""]; t (x:xs) = [x:xs] ++ t xs

还有一个将列表作为唯一参数。

t ls = [drop n ls|n<-[0..length ls - 1]]

【讨论】:

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