繁体   English   中英

Haskell中列表的元素加法(乘法,取幂等)

[英]Element-wise addition (multiplication, exponentiation, etc.) of lists in Haskell

如果我在Haskell中有两个相同大小的列表

list1 = [1.0,2.0,3.0]
list2 = [3.0,5.0,7.0]

我将如何执行元素添加以创建相同大小的第三个列表?

[4.0,7.0,10.0]

具体来说,我想做一个这样的功能:

listAdd :: [Float] -> [Float] -> [Float]
listAdd a b
    | length a /= length b = error "length mismatch"
    otherwise              = ????

我不知道该用什么代替“ ????”。 我认为它必须涉及'map'和某些版本的'+',但部分评估的东西让我感到困惑,而且正确的语法已经证明是难以捉摸的。

编辑1:

我以为我理解了与cons运算符匹配的模式,所以我接下来尝试了这个:

listAdd :: [Float] -> [Float] -> [Float]
listadd (x:xs) (y:ys) = (x+y) : listAdd xs ys
listAdd []     []     = []
listAdd _      _      = error "length mismatch"

但仍有一些问题,如

listAdd [1.0,2.0] [2.0,3.0]

越过有用的模式并返回错误。

编辑2:

随着错字的消除,

listAdd :: [Float] -> [Float] -> [Float]
listAdd (x:xs) (y:ys) = (x+y) : listAdd xs ys
listAdd []     []     = []
listAdd _      _      = error "length mismatch"

像宣传的那样工作。 由于在我研究的早期阶段,我无法管理任意维张量的类型,所以我决定仅将其扩展到矩阵加法:

mAdd :: [[Float]] -> [[Float]] -> [[Float]]
mAdd (x:xs) (y:ys) = listAdd x y : mAdd xs ys
mAdd []     []     = []
mAdd _      _      = error "length mismatch"

我意识到将功能捆绑在一起可能不是理想的选择,因为它降低了模块化/可移植性,但是可以满足我的需要。

编辑3:

我希望宣布某种程度的学习已经发生还为时过早。 我现在有这个:

listCombine :: (Float -> Float -> Float) -> [Float] -> [Float] -> [Float]
listCombine f (x:xs) (y:ys) = (f x y) : listCombine f xs ys
listCombine f []     []     = []
listCombine _ _      _      = error "length mismatch"

这可能与zipWith相同,只是它给出了不匹配长度的错误。 它处理了我遇到的一些极端情况,并获得了预期的结果。

单独计算参数列表的长度不是一个好主意。 我们通常希望尽可能少地使用输入,同时尽可能多地生成输出。 这被称为“不强迫输入”,即尽可能地懒惰。

在你的情况下,当我们分析这两个参数时,如果一个列表为空而另一个列表为空,我们将知道长度不匹配:

listAdd :: [Float] -> [Float] -> [Float]
listAdd (x:xs) (y:ys) =  (x+y) : listAdd ... ...
listAdd []     []     = []
listAdd _      _      =  error "length mismatch"

这样它甚至可以用于无限列表。

与此类似的内置函数是zipWith ,但它忽略了列表长度不匹配:

Prelude> zipWith(+) [1,2] [3]
[4]

它等同于上面的定义,最后两行用catch-all子句替换

listAdd _      _      = []

这不是原始问题,而是其中一条评论:增加了张量。 我对张量的理解是作为n维矩阵。 您已经知道元素添加只是zipWith一个应用程序。 但是我们可以使用applicative和functor类型类编写函数addLists

import Control.Applicative

addLists :: [Float] -> [Float] -> [Float]
addLists x y = (*) <$> x <*> y

或等效地:

addLists :: [Float] -> [Float] -> [Float]
addLists = liftA2 (*) 

请注意, <$> == fmap<*>Applicative类中。

首先,我们为等级0张量定义一个类型:

newtype Identity a = Identity {getIdentity :: a}

instance Functor Identity where 
  fmap f (Identity a) = Identity (f a) 

instance Applicative Identity where 
  pure a = Identity a
  (<*>) (Identity f) (Identity a) = Identity (f a)

然后是一个用于在等级n张量之上添加新层,创建等级n + 1张量的类型:

newtype Compose f g a = Compose {getCompose :: f (g a)}

instance (Functor f, Functor g) => Functor (Compose f g) where 
  fmap f (Compose a) = Compose (fmap (fmap f) a)

instance (Applicative f, Applicative g) => Applicative (Compose f g) where 
  pure a = Compose (pure (pure a))
  (<*>) (Compose f) (Compose a) = Compose (liftA2 (<*>) f a)

但等等,还有更多! 这些类型及其实例已经为您定义,即在Data.Functor.IdentityData.Functor.Compose 您现在可以编写通用张量元素添加:

addTensor :: Applicative f => f Float -> f Float -> f Float
addTensor = liftA2 (*) 

函数liftA2只是将zipWith推广到Applicative s。 对于等级1,您具有:

addTensor1 :: Compose [] Identity Float -> Compose [] Identity Float -> Compose [] Identity Float
addTensor1 = addTensor

这种类型有点吵。 您可以轻松定义类型同义词:

type Tensor0 = Identity
type Tensor1 = Compose [] Tensor0
type Tensor2 = Compose [] Tensor1
type Tensor3 = Compose [] Tensor2
type Tensor4 = Compose [] Tensor3

然后:

addTensor3 :: Tensor3 Float -> Tensor3 Float -> Tensor3 Float
addTensor3 = addTensor

addTensor4 :: Tensor4 Float -> Tensor4 Float -> Tensor4 Float
addTensor4 = addTensor

由于addTensor对所有Applicative抽象,因此您可能需要定义Applicative的子类,以形成有效的张量:

class Applicative t => Tensor t 
instance Tensor Identity
instance Tensor t => Tensor (Compose [] t)

addTensor :: Tensor f => f Float -> f Float -> f Float
addTensor = liftA2 (*) 

我怀疑除了加法之外,你可能还有其他的张量操作。 这种通用形式使得定义大范围的操作变得非常容易。 但假设你只想要addTensor你可以这样做:

class Tensor a where 
  addTensor :: a -> a -> a 

instance Tensor Float where 
  addTensor = (+)

instance Tensor t => Tensor [t] where 
  addTensor = zipWith addTensor 

更简单的类型结果是: addTensor :: [[[[Float]]]] -> [[[[Float]]]] -> [[[[Float]]]]

暂无
暂无

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

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