我编写了以下代码来查找haskell中列表的最后一个元素:
myLast (x:xs) = do
ret <- if xs == [] then x else (myLast xs)
return ret
我们的想法是遍历列表,直到我们处于一个以空列表作为下一个元素的元素。当我们找到它时,我们将ret
设置为该元素。
这对我来说很有意义,但是当我在交互式shell中运行代码时,我收到以下错误:
<interactive>:1:1: error:
• No instance for (Num (m0 b0)) arising from a use of ‘it’
• In a stmt of an interactive GHCi command: print it
编辑1
我使用do
的原因是因为我看到在某处使用该模式也遍历列表,所以我想我可以在这里做同样的事情。我现在正在避免使用图书馆来熟悉这门语言。
我写了避免do关键字的函数,现在它可以工作:
myLast(x:xs) = if xs == [] then x else (myLast xs)
现在只是空列表案例的问题。如何在haskell中解决这个问题?
答案 0 :(得分:2)
让我们从你的功能签名开始
myLast :: [a] -> a
现在,对于空列表输入,可以预期什么作为输出?如何组成任意类型a
的实例?
或者,您可以将丢失的最后一个元素的处理推迟到函数的调用者。
myLast :: [a] -> Maybe a
答案 1 :(得分:1)
你想要
myLast (x:xs) =
等于
if xs == [] then x else (myLast xs)
很好,xs == []
,所以让我们把它放回去:
myLast (x:[]) = x
但else
部分怎么样?好吧,让我们为此添加另一个等式,
myLast (_:xs) = myLast xs
我们是金色的。
如果我们用空列表[]
调用它会怎么样?没有定义案例匹配,我们将得到某种运行时错误。好吧,同样的事情也发生在内置函数last
上,所以我们在这里没有比Haskell本身更好和没有更差。
我提到的匹配是什么,你问?那就是如何调用Haskell函数。每个函数定义都可以有多个子句,从函数的名称开始,并包含每个预期参数的模式。
在等式的左边,
(x:[])
是一个匹配任何单例列表的模式。它也可以写成[x]
。 x
将引用列表中唯一的元素,如果在等式的右侧使用。
[]
是一种模式,匹配任何空列表。
(x:xs)
是一种模式,匹配任何非空列表。如果在等式的右侧使用,x
将引用列表的 head (即第一个)元素; xs
将引用列表中元素的 rest (也是列表 - 也称为 tail )。
但等等,你问。单个列表 匹配空列表,[x]
?
为什么是,他们两个确实匹配; (_:xs)
和xs
不互斥。
但是没关系,因为在Haskell中,如果第一个子句匹配,那就是 - 是执行的子句,没有其他尝试进行任何其他模式匹配和子句选择。
那将是Prolog,而那是另一种语言。