通过在Haskell中部分应用来减少列表

时间:2016-08-11 14:13:51

标签: haskell

对于具有多个参数的函数,是否有更强大的map版本?因此,缩小列表的长度为length of original / number of arguments ...

tuple a b = (a, b)
map' tuple [1, 2, 3, 4]
> [(1, 2), (3, 4)]

mul a b c = a * b * c
map' mul [1, 2, 3, 4, 5, 6]
> [3, 120]

我试着自己写一个,但似乎不可能接受任何数量的论点的功能。

我想为可变数量的参数设置通用版本,因为每次自己写一个需要一些时间而且它不会使用循环融合。

2 个答案:

答案 0 :(得分:4)

最简单的解决方案是生成辅助函数 对于你需要的每个arity,例如为arity 3功能:

map3 :: (a -> a -> a -> b) -> [a] -> [b]
map3 f (x : y : z : rest) = f x y z : map3 f rest
map3 f _ = []

将它们放在实用程序模块中,以便您可以根据需要导入它们。 如果你想变得复杂,你可以使用它来生成它们 TemplateHaskell,CPP宏,甚至类型类,但要小心 将这个简单的练习变成牦牛剃须派对。

你的例子:

interact $ unlines . fmap foo . tuple . lines

然后可表示为:

interact $ unlines . map2 foo . lines

假设foo具有签名foo :: String -> String -> String

答案 1 :(得分:4)

我不同意定义这样的东西的精神,但仅仅因为它的无意识,我正在尝试它。这是一个有效的解决方案,但仅适用于单形类型。我正在研究是否可以将其转换为涉及类型系列的东西,而且不需要使用类型注释。

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}

class Consumer f a b where
  consume :: f -> [a] -> Maybe (b,[a])

instance {-# OVERLAPPABLE #-} Consumer b a b where
  consume b xs = Just (b,xs)

instance {-# OVERLAPPING #-} Consumer f a b => Consumer (a -> f) a b where
  consume f [] = Nothing
  consume f (x:xs) = consume (f x) xs

map' :: Consumer f a b => f -> [a] -> [b] 
map' f xs = case consume f xs of
                Nothing -> []
                Just (b,xs') -> b : map' f xs'

并测试出来

> map' ((+) :: Int -> Int -> Int) ([1,2,3,4] :: [Int]) :: [Int]
[3,7]
> map' (id :: Int -> Int) ([1,2,3,4] :: [Int]) :: [Int]
[1,2,3,4]

修改

经过一番思考后,我认为不可能有更好的解决方案(没有依赖类型)。我必须在任何地方添加类型注释的原因是我无法通知GHC我提供的两个消费者实例实际上是我想要的实例(即使是封闭类型类也是如此)事情?)我无法蚀刻掉功能依赖。第二个问题也是我无法将其重写为类型族的原因。但是请注意,现在我们有TypeApplicationsmap' ((+) @Int) ([1..9] :: [Int])来注释函数参数会更好看。