Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Haskell中结束模式匹配_Haskell_Recursion - Fatal编程技术网

如何在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
混合其他模式匹配。