Haskell-如何使用Find声明Positions函数?

时间:2018-09-20 08:11:53

标签: haskell functional-programming

我对学习如何在Haskell中编程非常陌生。

我有一个方法positions的示例:

positions :: Eq a => a -> [a] -> [Int]
positions x xs = [i | (y, i) <- zip xs [0..], y == x]

我的目标是找到一种定义positions函数的方法,但要使用find方法。

find方法:

find :: Eq a => a -> [(a,b)] -> [b]
find k t = [v | (m, v) <- t, m == k]

有人可以解释仅使用 positions函数来声明find函数的方法吗?

我不明白如何使用find函数跟踪索引。

2 个答案:

答案 0 :(得分:2)

我们首先将positions重写为

positions x xs = map (\(_, i) -> i) . filter (\(y, _) -> y == x) $ zip xs [0..]

然后我们将find重新写为

find k t       = map (\(_, v) -> v) . filter (\(m, _) -> m == k) $ t
-- or,
find x         = map (\(_, i) -> i) . filter (\(y, _) -> y == x) 

,然后简单地注意到这两段代码完全相同(在重命名变量之后):

positions x xs = find x                                          $ zip xs [0..]

find仅接受的列表,然后过滤它们并提取第二个成分;您将必须使用 something (例如 zip )来生成find要处理的对。 没有解决方法。


当然,positions也可以不用zip部分进行编码(而不是使用mapAccumL进行编码),但是它不需要find

-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])

positions :: (Eq a) => a -> [a] -> [Int]
positions x = concat . snd . mapAccumL g 0 
  where
  g acc y = (acc+1, [acc | y == x])

我们可以使它人为地产生find所期望的列表,但是它将重做很多工作,并且只是对zip的枚举部分的重新实现(因此,而不是find本身。

答案 1 :(得分:2)

看:

positions x xs = [i | (y, i) <- zip xs [0..], y == x]
find      k t  = [v | (m, v) <- t           , m == k]

它们看起来很相似!通过在实现的过程中将k重命名为x,将m重命名为y,将v重命名为i,我们可以使其更加引人注目。 find

positions x xs = [i | (y, i) <- zip xs [0..], y == x]
find      x t  = [i | (y, i) <- t           , y == x]

所以现在很明显:我们要做的就是让positions传递zip xs [0..]作为t的{​​{1}}参数。

find