使用默认值而不是丢弃值来压缩?

Tor*_*enJ 15 haskell functional-programming list higher-order-functions

我正在寻找haskell中的函数来压缩两个长度可能不同的列表.
我可以找到的所有zip函数只删除比另一个更长的列表的所有值.

例如:在我的练习中,我有两个示例列表.
如果第一个比第二个短,我必须用0填充.否则我必须使用1.
我不允许使用任何递归.我只需要使用更高阶的函数.

我可以使用任何功能吗?
到目前为止,我真的找不到任何解决方案.

pig*_*ker 38

这个问题有一些结构,它来了.我会用这个东西:

import Control.Applicative
import Data.Traversable
import Data.List
Run Code Online (Sandbox Code Playgroud)

首先,list-with-padding是一个有用的概念,所以让我们有一个类型.

data Padme m = (:-) {padded :: [m], padder :: m} deriving (Show, Eq)
Run Code Online (Sandbox Code Playgroud)

接下来,我记得截断zip操作Applicative在库中产生了一个实例newtype ZipList(非流行的一个例子Monad).Applicative ZipList由无穷大和最小值给出的幺半群装饰的数量.Padme具有类似的结构,除了它的底层幺半群是正数(无穷大),使用一个和最大值.

instance Applicative Padme where
  pure = ([] :-)
  (fs :- f) <*> (ss :- s) = zapp fs ss :- f s where
    zapp  []        ss        = map f ss
    zapp  fs        []        = map ($ s) fs
    zapp  (f : fs)  (s : ss)  = f s : zapp fs ss
Run Code Online (Sandbox Code Playgroud)

我不得不说出通常的咒语来生成一个默认Functor实例.

instance Functor Padme where fmap = (<*>) . pure
Run Code Online (Sandbox Code Playgroud)

如此配备,我们可以垫!例如,采用一个参差不齐的字符串列表并用空格填充它们的函数就变成了一个字符串.

deggar :: [String] -> [String]
deggar = transpose . padded . traverse (:- ' ')
Run Code Online (Sandbox Code Playgroud)

看到?

*Padme> deggar ["om", "mane", "padme", "hum"]
["om   ","mane ","padme","hum  "]
Run Code Online (Sandbox Code Playgroud)


dup*_*ode 7

这可以使用These("表示具有两个非排他性可能性的值")和Align("支持拉链操作的仿函数,其中包含非均匀形状的联合")来表示这些库:

import Data.Align
import Data.These

zipWithDefault :: Align f => a -> b -> f a -> f b -> f (a, b)
zipWithDefault da db = alignWith (fromThese da db)
Run Code Online (Sandbox Code Playgroud)

salign其他专业的对齐Data.Align也值得一看.

感谢你/ WarDaft,u/gallais和u/sjakobi在r/haskell指出这个答案应该存在于此.


Lee*_*Lee 6

您可以在每个列表中附加0或1的inifinte列表,然后从结果压缩列表中获取所需的数字:

zipWithDefault :: a -> b -> [a] -> [b] -> [(a,b)]
zipWithDefault da db la lb = let len = max (length la) (length lb)
                                 la' = la ++ (repeat da)
                                 lb' = lb ++ (repeat db)
                             in take len $ zip la' lb'  
Run Code Online (Sandbox Code Playgroud)


Cli*_*ton 6

这应该可以解决问题:

import Data.Maybe (fromMaybe)

myZip dx dy xl yl = 
  map (\(x,y) -> (fromMaybe dx x, fromMaybe dy y)) $ 
    takeWhile (/= (Nothing, Nothing)) $ 
    zip ((map Just xl) ++ (repeat Nothing)) ((map Just yl) ++ (repeat Nothing))

main = print $ myZip 0 1 [1..10] [42,43,44]
Run Code Online (Sandbox Code Playgroud)

基本上,将无限列表附加Nothing到两个列表的末尾,然后压缩它们,并在两个都为时删除结果Nothing。然后,将Nothings 替换为适当的默认值,并删除不再需要的Justs。