在Haskell中用填充进行压缩 [英] Zipping with padding in Haskell

查看:83
本文介绍了在Haskell中用填充进行压缩的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有几次,我发现自己希望Haskell中的 zip 能够将填充添加到较短的列表中,而不是截断较长的填充。这很容易写。 ( Monoid 在这里适用于我,但您也可以传入要用于填充的元素。)

  zipPad ::(Monoid a,Monoid b)=> [a]  - > [b]  - > [(a,b)] 
zipPad xs [] = zip xs(重复空格)
zipPad [] ys = zip(重复空格)ys
zipPad(x:xs)(y: ys)=(x,y):zipPad xs ys

这种方法在尝试定义 zipPad3 。我输入了以下内容,然后意识到它当然不起作用:

  zipPad3 ::(Monoid a,Monoid b ,Monoid c)=> [a]  - > [b]  - > [c]  - > [(a,b,c)] 
zipPad3 xs [] [] = zip3 xs(repeat mempty)(repeat mempty)
zipPad3 [] ys [] = zip3(repeat mempty)ys(repeat mempty )
zipPad3 [] [] zs = zip3(重复记忆)(重复记忆)zs
zipPad3 xs ys [] = zip3 xs ys(重复记忆)
zipPad3 xs [] zs = zip3 xs(重复mempty)zs
zipPad3 [] ys zs = zip3(重复mempty)ys zs
zipPad3(x:xs)(y:ys)(z:zs)=(x,y,z ):zipPad3 xs ys zs

在这一点上,我欺骗并使用 length 选择最长的列表并填充其他列表。



我忽略了一种更优雅的方式来做到这一点,或者像 zipPad3 已经在某处定义了?

解决方案

定制头像如何和尾部函数(命名为 next rest 在下面的例子中)?

pre $ import Data.Monoid

zipPad ::(幺半群a,幺半群b)=> [a] - > [b] - > [(a,b)]
zipPad [] [] = []
zipPad xs ys =(next xs,next ys):zipPad(rest xs)(rest ys)

zipPad3 ::(Monoid a,Monoid b,Monoid c)=> [a] - > [b] - > [c] - > [(a,b,c)]
zipPad3 [] [] [] = []
zipPad3 xs ys zs =(next xs,next ys,next zs):zipPad3(rest xs)(rest ys)(rest zs)

next ::(Monoid a)=> [a] - > a
next [] = mempty
next xs = head xs

rest ::(Monoid a)=> [a] - > [a]
rest [] = []
rest xs = tail xs

测试片段:

  instance Monoid Int其中
mempty = 0
mappend =(+)

main = do
print $ zipPad [1,2,3,4 :: Int] [1,2 :: Int]
print $ zipPad3 [1,2,3, 4 :: Int] [9 :: Int] [1,2 :: Int]



  [(1,1),(2,2),(3,0),(4,0)] 
[(1,9,1),(2,0,2),(3,0,0),(4,0,0)]
pre>

A couple of times I've found myself wanting a zip in Haskell that adds padding to the shorter list instead of truncating the longer one. This is easy enough to write. (Monoid works for me here, but you could also just pass in the elements that you want to use for padding.)

zipPad :: (Monoid a, Monoid b) => [a] -> [b] -> [(a, b)]
zipPad xs [] = zip xs (repeat mempty)
zipPad [] ys = zip (repeat mempty) ys
zipPad (x:xs) (y:ys) = (x, y) : zipPad xs ys

This approach gets ugly when trying to define zipPad3. I typed up the following and then realized that of course it doesn't work:

zipPad3 :: (Monoid a, Monoid b, Monoid c) => [a] -> [b] -> [c] -> [(a, b, c)]
zipPad3 xs [] [] = zip3 xs (repeat mempty) (repeat mempty)
zipPad3 [] ys [] = zip3 (repeat mempty) ys (repeat mempty)
zipPad3 [] [] zs = zip3 (repeat mempty) (repeat mempty) zs
zipPad3 xs ys [] = zip3 xs ys (repeat mempty)
zipPad3 xs [] zs = zip3 xs (repeat mempty) zs
zipPad3 [] ys zs = zip3 (repeat mempty) ys zs
zipPad3 (x:xs) (y:ys) (z:zs) = (x, y, z) : zipPad3 xs ys zs

At this point I cheated and just used length to pick the longest list and pad the others.

Am I overlooking a more elegant way to do this, or is something like zipPad3 already defined somewhere?

解决方案

How about custom head and tail functions (named next and rest in my example below)?

import Data.Monoid

zipPad :: (Monoid a, Monoid b) => [a] -> [b] -> [(a,b)]
zipPad [] [] = []
zipPad xs ys = (next xs, next ys) : zipPad (rest xs) (rest ys)

zipPad3 :: (Monoid a, Monoid b, Monoid c) => [a] -> [b] -> [c] -> [(a,b,c)]
zipPad3 [] [] [] = []
zipPad3 xs ys zs = (next xs, next ys, next zs) : zipPad3 (rest xs) (rest ys) (rest zs)

next :: (Monoid a) => [a] -> a
next [] = mempty
next xs = head xs

rest :: (Monoid a) => [a] -> [a]
rest [] = []
rest xs = tail xs

Test snippet:

instance Monoid Int where
  mempty = 0
  mappend = (+)

main = do
  print $ zipPad [1,2,3,4 :: Int] [1,2 :: Int]
  print $ zipPad3 [1,2,3,4 :: Int] [9 :: Int] [1,2 :: Int]

Its output:

[(1,1),(2,2),(3,0),(4,0)]
[(1,9,1),(2,0,2),(3,0,0),(4,0,0)]

这篇关于在Haskell中用填充进行压缩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆