【问题标题】:How to deal with recursing through a list in Haskell (transpose operation)如何通过Haskell中的列表处理递归(转置操作)
【发布时间】:2019-01-04 09:08:41
【问题描述】:

虽然我知道 Haskell 中可能有转置或 ZipList 函数,但我正在尝试构建自己的转置函数,它将采用 n 个等长 m 列表和将它们转置为长度为 nm 个列表。

到目前为止,我的功能几乎可以使用以下代码:

list = [[1,2,3],[4,5,6],[7,8,9]]

head' (x:xs) = x

head'' [] = []
head'' (xs:lxs) = head' xs:head'' lxs

tail' [] = []
tail' (x:xs) = xs

tail'' [] = []
tail'' (xs:lxs) = tail' xs:tail'' lxs

merge (xs:lxs) = (head' xs:head'' lxs):(merge (tail' xs:tail'' lxs))

当我在 ghci 中运行 > merge list 时得到以下输出:

[[1,4,7],[2,5,8],[3,6,9],[*** Exception: list2.hs:16:1-16: Non-exhaustive patterns in function head'

我很确定这意味着我的head' 函数上的空列表的基本情况丢失了。该列表被转置,只是没有关闭。在这种情况下,我该如何处理这个问题?我有一种预感,它可能与 Maybe 有关,但我无法以这种方式实现它。

【问题讨论】:

  • head' (x:xs) = x,但head' [] 是什么?
  • 由于head' xs:head'' lxs = head'' (xs:lxs),您可以将merge (xs:lxs) = (head' xs:head'' lxs):...折叠成merge (xs:lxs) = (head'' (xs:lxs)):...。类似的等式推理适用于...,给出merge (xs:lxs) = (head'' (xs:lxs)):(tail'' (xs:lxs))。在这一点上,模式匹配没有多大意义。 merge lxs = head'' lxs:tail'' lxs。但是现在你绝对应该怀疑:merge 的这个定义显然总是调用(:) 而从不调用[]。那么如何到达merge 输出的“结尾”呢?

标签: list haskell recursion transpose non-exhaustive-patterns


【解决方案1】:

需要添加退出条件:

merge [] = []
merge ([]:xss) = merge xss

【讨论】:

  • 那么与merge 的其他两个定义相比,merge ([]:xss) = merge xss 何时运行?
【解决方案2】:

除了现有的headtail 函数之外,您只需要map。为简单起见,假设输入始终是一个非空列表(即,xs 可能是[[],[],[]],但绝不是单独使用[],因此使用headtail 没有问题。)

> map head list
[1,4,7]
> map tail list
[[2,3],[5,6],[8,9]]
> let foo xs = if null (head xs) then [] else map head xs : foo (map tail xs)
> foo list
[[1,4,7],[2,5,8],[3,6,9]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    • 2016-06-18
    • 2017-02-10
    • 2011-07-16
    • 1970-01-01
    • 2019-07-21
    相关资源
    最近更新 更多