简体   繁体   English

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

[英]Reduction of list through partial application in Haskell

Is there some more powerful version of map for functions with multiple arguments? 对于具有多个参数的函数,是否有一些功能更强大的map? Thus the length of the reduced list would be length of original / number of arguments ... 因此,精简列表的长度将是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]

I tried to write myself one, but it seems impossible to accept function of any number of arguments. 我试图为自己写一个,但是似乎无法接受任何数量的参数的功能。

I would like to have generic version for variable number of arguments, because writing one myself every time takes some time and it won't use loop fusion. 我想为可变数量的参数提供通用版本,因为每次自己编写一个会花费一些时间,并且不会使用循环融合。

The simplest solution is to just generate a helper function for each arity that you need, eg for arity 3 functions: 最简单的解决方案是只为您需要的每个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 _ = []

Put these in a utility module so you can import them as needed. 将它们放在实用程序模块中,以便您可以根据需要导入它们。 If you want to get sophisticated you can generate them using TemplateHaskell, CPP macros, or even type-classes, but be careful about turning this simple exercise into a yak shaving party. 如果您想变得复杂,可以使用TemplateHaskell,CPP宏甚至类型类来生成它们,但是要小心,不要将这个简单的练习变成a牛刮胡子聚会。

Your example: 你的例子:

interact $ unlines . fmap foo . tuple . lines

could then be expressed as: 然后可以表示为:

interact $ unlines . map2 foo . lines

assuming that foo has the signature foo :: String -> String -> String 假设foo具有签名foo :: String -> String -> String

I disagree with the spirit of defining something like this, but just for the hasochism of it, I'm trying my hand at it. 我不同意定义这样的东西的精神,但是仅仅出于它的狭och性,我正在努力尝试它。 Here is a solution that works, but only for monomorphic types. 这是一个有效的解决方案,但仅适用于单态类型。 I'm working on seeing if I can convert it to something involving type families that also doesn't need to be littered with type annotations. 我正在研究是否可以将其转换为涉及类型族的东西,这些类型族也不需要乱用类型注释。

{-# 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'

And testing it out 并进行测试

> 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]

EDIT 编辑

After some thought, I don't think that a better solution is possible (without dependent types). 经过一番思考,我认为不可能有更好的解决方案(没有依赖类型)。 The reason I have to add type annotations everywhere is that I have no way of informing GHC that the two consumer instances I've provided are actually the only instances I will ever want (are closed type classes even a thing?) and I can't etch out functional dependencies. 我之所以要到处添加类型标注的是,我没有办法告知GHC的,我已经提供的两个实例消费者其实我都不会想的唯一实例(是密闭式班甚至一个东西吗?)我可以”提取功能依赖性。 This second problem is also why I can't rewrite this as a type family. 第二个问题也是为什么我不能将其重写为类型族。 On a side note though, annotating the function arguments can look a lot nicer now that we have TypeApplications : map' ((+) @Int) ([1..9] :: [Int]) . 在一个侧面说明,虽然,注释功能参数可以看起来要好很多,现在我们有TypeApplicationsmap' ((+) @Int) ([1..9] :: [Int])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM