【发布时间】:2011-01-21 23:42:44
【问题描述】:
我已经完成了“真实世界的haskell”的一半,并认为我应该尝试编写我的第一个代码。没走多远……
基本上,我想我会尝试为双精度和双精度列表实现数组语法,这样我就可以对列表进行数值计算。我是否认为“类”就像 CLOS 中的通用函数?我用函数 arplus 创建了一个“类”来添加数组和标量,并使其适用于标量。现在我不知道如何对列表做同样的事情。 (计算很简单,我只是不知道在列表版本中用什么代替“双”)。
class Narray a where
arplus :: a -> a -> a
instance Narray Double where
arplus a b = a + b
那么,我该如何做混合版本呢?数组标量和标量数组?
我需要类似的东西吗:
class Narray a where
arplus :: a -> b -> a
改为?
作为我尝试编写的代码示例,请参见下面的 sbcl 代码: (注意 - 我已经用 lisp 中的数组完成了此操作,但我是在键入它们时在 haskell 中的列表中执行此操作的。就问题而言,这并不重要。)
;; Generic add for arrays and scalar
(defgeneric .+ (a b))
;; Scalar-scalar
(defmethod .+ ((a double-float) (b double-float)) (+ a b))
;; Array-array
(defmethod .+ ((a SB-KERNEL::SIMPLE-ARRAY-DOUBLE-FLOAT)
(b SB-KERNEL::SIMPLE-ARRAY-DOUBLE-FLOAT))
(dotimes (i (array-total-size a))
(setf (row-major-aref a i)
(+ (row-major-aref a i)
(row-major-aref b i)))) a)
;; Array-scaler
(defmethod .+ ((a SB-KERNEL::SIMPLE-ARRAY-DOUBLE-FLOAT) (b double-float))
(dotimes (i (array-total-size a))
(setf (row-major-aref a i)
(+ (row-major-aref a i)
b))) a)
;; Scalar-array
(defmethod .+ ((a double-float) (b SB-KERNEL::SIMPLE-ARRAY-DOUBLE-FLOAT))
(dotimes (i (array-total-size b))
(setf (row-major-aref b i)
(+ a
(row-major-aref b i)))) b)
;; Just to demo the code
(defun indgen (n)
(let ((r (make-array n :element-type 'double-float)))
(dotimes (i n)
(setf (row-major-aref r i) (coerce i 'double-float))) r))
* (load "arrays.lisp")
T
* (.+ (indgen 6) 10d0)
#(10.0d0 11.0d0 12.0d0 13.0d0 14.0d0 15.0d0)
* (.+ (indgen 6) (indgen 6))
#(0.0d0 2.0d0 4.0d0 6.0d0 8.0d0 10.0d0)
*
【问题讨论】:
-
附带说明,当您使用 Learn You A Haskell 来补充材料时,我发现 Real World Haskell 工作得非常好。
-
您尝试做的事情并不能很好地与haskell 的“说出你的意思”理念相匹配。数组数组加法(压缩)是与标量数组加法(映射)不同的概念。因此,您将需要两个单独的运算符。当前约定在向量参数的一侧使用
^:例如。^+^用于数组数组,+^用于标量数组。 -
AFAIK Haskell 不支持多种类型的分派,您可以编写类似
class Narray a b c where arplus :: a -> b -> c的内容,但您必须明确标记所有类型。 -
@adamax:没有必要明确标记所有类型;只是知道所有类型。如果你写
arplus True () ++ "abc"之类的东西,它会推断出Bool -> () -> String就好了。问题是指定对于每个特定的a和b,只有一个有效的c。
标签: haskell