如何让函数[a] - > [a]对[(a,Int)]进行操作?

Lan*_*dei 11 haskell abstraction

我发现自己经常按照模式编写代码:

foo xs = map snd $ filter ((< 10).fst) $ zip xs [0..]

bar ys = map snd $ sortBy (compare `on` fst) $ zip ys [0..]
Run Code Online (Sandbox Code Playgroud)

现在我想抽象出来

foo = indexesOf (filter (<10))

bar = indexesOf sort

indexesOf :: ([a] -> [a]) -> [a] -> [Int] 
indexesOf f xs = map snd $ magick $ zip xs [0..] where
    magick = undefined
Run Code Online (Sandbox Code Playgroud)

怎么magick办?

ham*_*mar 11

您的类型签名不起作用.您需要能够为传递的函数提供元组列表,这意味着您必须使用更高级别的类型来强制它变为多态,或者在类型签名中明确提及元组.

如果没有这个,你不能"查看"函数,看看它如何重新排列列表的元素.实际上,根据你的类型签名,传递的函数可以对列表做任何想做的事情,包括插入那些甚至不在那里的元素!

这是我使用更高级别类型工作的内容:

{-# LANGUAGE RankNTypes #-}

import Data.List (sortBy)
import Data.Ord (comparing)

indexesOf :: (forall b. (b -> a) -> [b] -> [b]) -> [a] -> [Int]
indexesOf f xs = map snd $ f fst $ zip xs [0..]

foo :: (Ord a, Num a) => [a] -> [Int]
foo = indexesOf (filter . ((< 10) .))

bar :: Ord a => [a] -> [Int]
bar = indexesOf (sortBy . comparing)
Run Code Online (Sandbox Code Playgroud)

请注意,我还必须向传递的函数添加一个额外的参数,以告诉它如何从它正在处理的列表的元素中提取它关心的部分.如果没有这个,你将只能使用不检查列表元素的函数,例如reverse,并且这些函数不会非常有用.

示例在GHCi中运行:

> let xs = [42, 0, 7, 3, 12, 17, 99, 36, 8]
> foo xs
[1,2,3,8]
> bar xs
[1,3,2,8,4,5,7,0,6]
> indexesOf (const reverse) xs
[8,7,6,5,4,3,2,1,0]
Run Code Online (Sandbox Code Playgroud)