【发布时间】:2015-07-17 20:50:43
【问题描述】:
一段时间后,我决定重新学习一些函数式编程。这次我决定选择 Haskell,因为它的特性和 .. 语法。
目前我正在做一些练习,但我被卡住了。我想编写一个从列表中选择倒数第二个元素的函数,即给定 [1,2,3,4] 它将是 3。
这是我的功能。
lastButOne xs
| null xs = xs
| length xs == 1 = xs
| length xs == 2 = lastButOne head xs
| otherwise = lastButOne tail xs
不幸的是,它会产生一些错误。
Couldn't match expected type `[a]' with actual type `[a1] -> [a1]'
Relevant bindings include
xs :: [a] (bound at lastButOne.hs:1:12)
lastButOne :: [a] -> [a] (bound at lastButOne.hs:1:1)
Probable cause: `tail' is applied to too few arguments
In the first argument of `lastButOne', namely `tail'
In the expression: lastButOne tail xs
我尝试过一些部分性,例如 (head xs) 和 (tail xs),但没有帮助。
Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [[a]]
Actual type: [a]
Relevant bindings include
xs :: [a] (bound at lastButOne.hs:1:12)
lastButOne :: [a] -> [a] (bound at lastButOne.hs:1:1)
In the first argument of `head', namely `xs'
In the first argument of `lastButOne', namely `(head xs)'
跟进: 或者我应该写后续的。好吧,我最初的想法是编写一个函数,如果列表长度为 1,则该函数会产生头元素。因此,鉴于 Lee 的解释,很容易得出以下结论:
lastPattern :: [a] -> Maybe a
lastPattern [] = Nothing
lastPattern [x] = Just x
lastPattern [x,_] = Just x
lastPattern (_:xs) = lastPattern xs
这是第一个问题。 条件 [x] 和 [x,_] 的模式是什么?
接下来我想做的是用相反的方式编写相同的函数(正如 Paul Johnson 所指出的)。我很快想出了head (tail (reverse [1,2,3,4])),它似乎在 REPL 中运行良好。但是当我开始一些编码时,我最终得到了
lastRev :: [a] -> a
lastRev xs
| null xs = error "empty list"
| length xs == 1 = error "too short"
| otherwise = head (tail (reverse xs))
因为 head 函数是 head :: [a] -> a 。上面的功能对我的口味来说有点乱,可以这么说。 有什么办法可以让我成为:: [a] -> Maybe a 吗?这是第二个问题。
最后但并非最不重要的 - 第三个问题。 哪个函数在性能方面更好?我如何在 Haskell 中测量它?
【问题讨论】:
-
有什么理由不能使用“reverse”?
-
没有特别的原因。正如我所写,我只是在学习,我想实现这种“我的”方式,而不是“最好的”或“正确的”方式。我只是想更好地理解语言。也许我会在几分钟内用反向功能解决这个问题。所以谢谢你指出这一点。 :)
标签: haskell