如何映射带有两个参数(而不是一个)的函数?

我有一个 Haskell 问题,我想出了一个解决方案,但我就是不能把笔写在纸上。

基本上我有一个函数calc,它接受一个Int并返回一个Float.

calc :: Int -> Int -> Float 
calc :: Int -> Int -> Float 

在我的函数中,g我想将此函数应用于数组

g :: [Int] -> [Float]

由于calc需要两个Int参数,我想消耗两个Ints(
x作为数组的第一个索引和x+1第二个索引)。这将继续在(数组索引)[1][2], [2][3], [3][4]等上重复该函数。

我试过在网上研究如何使用map,它基本上是这样说的?知道为什么代码不想编译,x+1甚至是可行的吗?

回答

一元映射是map二元映射是zipWith。那么什么是拉链?同一列表的两个副本,一个位置相对另一个位置偏移:

calc :: Int -> Int -> Float
g :: [Int] -> [Float]
g xs = zipWith calc xs (drop 1 xs)

这就是全部。当较短的序列用完时,压缩会自动停止。

zipWith foo适用foo于每一对参数,每个参数来自相应的列表,一个接一个的元素。它可以使用zip作为实现

zipWith foo xs ys  =  map ( (x,y) -> foo x y) $ zip xs ys
                   =  [ foo x y | (x,y) <- zip xs ys ]

但它自己已经做到了。

作为一个例子,drop 1 [1,2,3] == [2,3]这意味着

zipWith calc [1, 2, 3] (drop 1 [1, 2, 3]) ==
zipWith calc [1, 2, 3] 
             [2, 3   ] ==
        [calc 1 
              2, 
            calc 2 
                 3]

您想使用索引。索引实际上从未在 Haskell 中与列表一起使用。我们改为通过结构抖动实现相同的效果,然后当我们沿着两个列表一次一个元素前进时,每次操作都是O(1),因为下一个元素已经在高级列表的顶部。而对于索引,我们每次都必须从顶部重新遍历相同的列表,导致每个( th ) 元素的O(k)时间,即整体二次行为。k


更新:采用压缩方法导致代码融合的可能性,

g2 xs  =  zipWith calc xs (drop 1 xs)
       =  [calc x y | (x,y) <- zip xs (drop 1 xs)]
       =  [calc x y | (x:y:_) <- tails xs]  -- tails ~= iterate (drop 1)

因为当它们已经出现在结构中时,为什么要构建一个新结构来容纳两个连续元素......原始列表结构。

有趣的是,Common Lisp 有这种特殊的映射,尾部映射,作为语言的一部分。虽然常规地图在那里被称为mapcar,但尾巴上的地图在那里被称为maplist(准确地说,它是非空尾巴上的地图)。


以上是如何映射带有两个参数(而不是一个)的函数?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>