例如:在我的练习中,我有两个示例列表 . 如果第一个比第二个短,我必须使用0 's. Otherwise I have to use 1' s填充 . 我不允许使用任何递归 . 我只需要使用更高阶的函数 .
我可以使用任何功能吗? 到目前为止我真的找不到任何解决方案 .
7 回答
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'
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
这可以使用这些库中的These("represents values with two non-exclusive possibilities")和Align("functors supporting a zip operation that takes the union of non-uniform shapes")来表示:
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)
type Result = [Int] -> [(Int,Int)]
myZip :: [Int] -> Result
myZip [] = map (\y -> (0,y)) -- :: Result
myZip (x:xs) = f x (myZip xs) -- :: Result
where f x k = ??? -- :: Result
一旦找到了f,请注意你可以将上面的递归变成折叠!
36
这是另一个解决方案,它可以在无限列表上工作,并且是Prelude的zip函数的简单升级:
zipDefault :: a -> b -> [a] -> [b] -> [(a,b)]
zipDefault _da _db [] [] = []
zipDefault da db (a:as) [] = (a,db) : zipDefault da db as []
zipDefault da db [] (b:bs) = (da,b) : zipDefault da db [] bs
zipDefault da db (a:as) (b:bs) = (a,b) : zipDefault da db as bs
和
zipDefaultWith :: a -> b -> (a->b->c) -> [a] -> [b] -> [c]
zipDefaultWith _da _db _f [] [] = []
zipDefaultWith da db f (a:as) [] = f a db : zipDefaultWith da db f as []
zipDefaultWith da db f [] (b:bs) = f da b : zipDefaultWith da db f [] bs
zipDefaultWith da db f (a:as) (b:bs) = f a b : zipDefaultWith da db f as bs
7 回答
您可以在每个列表中附加0或1的inifinte列表,然后从结果压缩列表中获取所需的数字:
这个问题有一些结构,它来了 . 我会用这些东西:
首先,list-with-padding是一个有用的概念,所以让我们有一个类型 .
接下来,我记得truncating-
zip
操作在库中产生Applicative
实例,如newtype ZipList
(非Monad
的一个流行示例) .Applicative ZipList
相当于由无穷大和最小值给出的幺半群的装饰 .Padme
具有类似的结构,除了它的底层幺半群是正数(无穷大),使用一个和最大值 .我不得不说出通常的咒语来生成一个默认的
Functor
实例 .如此装备,我们可以垫!例如,采用一个参差不齐的字符串列表并用空格填充它们的函数就变成了一个字符串 .
看到?
这可以使用这些库中的These("represents values with two non-exclusive possibilities")和Align("functors supporting a zip operation that takes the union of non-uniform shapes")来表示:
salign和
Data.Align
中的其他专业对齐也值得一看 .感谢你/ WarDaft,u / gallais和u / sjakobi在r / haskell指出这个答案应该存在于此 .
这应该是诀窍:
基本上,将
Nothing
的无限列表追加到两个列表的末尾,然后压缩它们,并在两者都是Nothing
时删除结果 . 然后用适当的默认值替换Nothing
,在你使用时丢弃不再需要的Just
.正如你自己所说,标准
zip :: [a] -> [b] -> [(a, b)]
从较长的列表中删除元素 . 要修改此事实,您可以在将输入提供给zip
之前修改输入 . 首先,您必须找出哪个列表较短(最有可能,使用length
) . 例如 . ,其中
x
是较短的xs
的默认值,y
是较短的ys
的默认值 .然后使用所需的默认元素扩展较短的列表(足以考虑其他列表的其他元素) . 在不必知道较长列表的长度的情况下这样做的巧妙技巧是使用函数
repeat :: a -> [a]
,它经常无限地重复其参数 .您不必比较列表长度 . 尝试将您的zip函数视为只接受一个参数
xs
并返回一个函数的函数,该函数将获取ys
并执行所需的zip . 然后,尝试编写一个递归函数,仅在xs
上进行递归,如下所示 .一旦找到了f,请注意你可以将上面的递归变成折叠!
这是另一个解决方案,它可以在无限列表上工作,并且是Prelude的zip函数的简单升级:
和
@pigworker,谢谢你的启发解决方案!