2012-02-17 57 views
11

我发现自己经常写代码如下格局:如何让函数[a] - > [a]在[(a,Int)]上运行?

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

bar ys = map snd $ sortBy (compare `on` fst) $ zip ys [0..] 

现在我想摘要远

foo = indexesOf (filter (<10)) 

bar = indexesOf sort 

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

如何执行magick

+0

...我真的不清楚是什么你正在努力去做。 – 2012-02-17 08:25:06

+0

我有一个函数在列表上工作,比如'sort'。现在,而不是排序的列表,我想获取元素的*索引*。例如。对于'[5.0,8.0,7.0]'我不想'[5.0。 7.0,8.0]',但是[0,2,1]'。 – Landei 2012-02-17 08:38:33

回答

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) 

请注意,我也有一个额外的参数添加到传递函数来告诉它如何提取它关心从部分它正在处理的列表中的元素。没有这个,你只能使用不检查列表元素的函数,比如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] 
+0

我想你在回答标题中的问题。 – 2012-02-17 10:21:33

+0

(继续)...但在给出的例子中,函数实际上是:: ::(Ord a)=> [a] - > [a]'。所以你可以“看看里面”。 – 2012-02-17 10:33:19

+0

@RafaelCaetano:您仍然需要能够通过更高级的类型或通过明确提及类型签名中的元组来选择不同的'a'。您可以创建类型签名'indexOf ::(forall b。Ord b => [b] - > [b]) - > [a] - > [Int]',但这只适用于'sort'示例,而不是使用'filter'的函数,因为函数只能将元素与eachother进行比较。它无法与'10'进行比较。 – hammar 2012-02-17 12:24:01

4

大的问题,但我怀疑存在没有这样的功能。 见Theorems For Free!。像锤子一样,你需要传递明确带有元组的元素。

这里是我的略微简化的版本,不需要RankNTypes(这是无可否认的,而不是在原来的代码很好的改善):

import Data.List 
import Data.Ord 

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

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

bar :: Ord a => [a] -> [Int] 
bar = indexesOf $ sortBy $ comparing fst 
+1

这是正确的,虽然更高级别的类型给你稍微强大的保证,因为函数不能混淆整数。它所能做的就是重新排序,复制和删除列表中的现有项目。 – hammar 2012-02-17 12:26:23

+0

的确如此。另外,当有一个类型为 - > Int的函数时,它必须是微不足道的,即一个常量(或未定义)。 – mnish 2012-02-17 13:51:57

相关问题