如何在Haskell中结束模式匹配
我需要实现一个函数,获取元素如何在Haskell中结束模式匹配,haskell,recursion,Haskell,Recursion,我需要实现一个函数,获取元素elt和列表lst,并返回lst中第一次出现elt的位置 我的答案是: elementPosition :: Eq t => t ->[t] -> Int elementPosition t [] = 0 elmentPosition t lst | t == head lst = 1 | otherwise = (elementPosition t (tail lst))+1 但是,如果elt不在lst中,我需要返
elt
和列表lst
,并返回lst
中第一次出现elt
的位置
我的答案是:
elementPosition :: Eq t => t ->[t] -> Int
elementPosition t [] = 0
elmentPosition t lst
| t == head lst = 1
| otherwise = (elementPosition t (tail lst))+1
但是,如果elt
不在lst
中,我需要返回0。但此代码将返回lst
的长度。当第一个模式匹配时,我可以做些什么来返回0
?如果没有,如何实现此功能?请尝试以下操作:
elementPosition :: Eq t => Int -> t -> [t] -> Int
elementPosition _ _ [] = 0
elementPosition pos key (x:xs)
| key == x = pos
| otherwise = elementPosition (pos + 1) key xs
然后
element位置0
将执行您想要执行的操作您必须将递归转换为尾部递归,以便在堆栈的顶部而不是底部做出最终决定。这样,您需要将当前从列表头累积的距离作为参数传递(当找到匹配项时,您需要此距离,但如果没有,则可以放弃此距离)。差不多
elementPosition :: Eq t => t ->[t] -> Int
elementPosition pat lst = elementPosition' 1 pat lst where
elementPosition' _ _ [] = 0
elementPosition' i pat (h:t) | pat == h = i
| otherwise = elementPosition' (i + 1) pat t
但请注意,标准库已经包括:
import Data.List
elementPosition :: Eq t => t ->[t] -> Int
elementPosition p l = maybe 0 succ $elemIndex p l
其他答案讨论了如何通过添加累加器来实现这一点。然而,我认为看到如何在没有累加器的情况下做到这一点也很有启发性;诀窍就是检查递归调用的返回值是否为
0
,如果是,则保持该值,而不是递增。因此:
elementPosition :: Eq t => t -> [t] -> Int
elementPosition t [] = 0
elementPosition t lst
| t == head lst = 1
| otherwise = case elementPosition t (tail lst) of
0 -> 0
n -> n+1
此外,使用
zip
(使列表成为元素及其索引的元组列表)和filter
(过滤掉我们正在寻找的值),我们可以得到以下定义:
elementPosition :: Eq t => t -> [t] -> Int
elementPosition e xs =
case filter ((== e) . fst) xsIndexed of
[] -> 0
(_, i):_ -> i
where xsIndexed = zip xs [1..]
正如@dfeuer所建议的,我们可以在一行中得到:
import Data.Maybe
elementPosition :: Eq t => t -> [t] -> Int
elementPosition e = maybe 0 fst . listToMaybe . filter ((== e) . snd) . zip [1..]
我认为正确的解决方案不是使用
0
来表示元素丢失(这会导致Int
结果有两种可能的含义)。这就是为什么bipll提到的elemIndex
函数返回的是Maybe Int
,而不是Int
。一般来说,如果您使用head
和tail
,那么您可能是在以一种非惯用的方式进行操作。这些是危险的局部函数,应尽可能避免。在这里,(x:xs)
上的模式匹配将简化代码,并删除部分函数。我看到:0
表示无
,而n+1
仅表示n
。这利用了标准的双射可能是Nat->Nat
。使用也许
s会更容易理解,不过:)@Albert,你到底在说什么?你要用他的密码,尽量不被抓住?除了学术上的诚实问题,这是一个很好的激怒网站和其他地方人们的方法。@Albert对不起,什么?否:如果你不被允许剽窃,那么解决办法就是不剽窃;我、你的导师、本网站的规则以及你良好的教育都不能接受你剽窃并试图隐瞒的解决方案。如果你从这个答案中学到了什么,我很高兴;但你有责任以合乎道德的方式提出问题,并以合乎道德的方式使用答案。@DanielWagner我为我不合理的要求道歉。我没有意识到分享的重要性,只是想完成我的工作。我知道这个地方非常适合分享我们的想法和交流。虽然我是这里的新手,但我应该知道这一点。再次抱歉,你的回答确实帮了我很大的忙,我会以正确的方式使用它。我希望我能从你身上学到更多。我建议在递归之前强制执行pos
,否则你会得到讨厌的重击otherse=pos`seq`elementPosition(pos+1)key xs
如果您选择该样式,您可以使用maybe
与listToMaybe
混合其他模式匹配。