我想知道是否可以编写一个 Haskell 加法运算符来处理两个数字、两个数字列表、两个数字矩阵……等等。也就是说,是否可以定义一个 <+>
使得以下所有工作?:
1 <+> 2 = 3
[1] <+> [2] = [3]
[[1]] <+> [[2]] = [[3]]
...
我知道 What is an idiomatic way to add lists in Haskell? ,我们可以做到+
对于 a
, zipWith (+)
对于 [a]
.大概 zipWith (zipWith (+))
对于 [[a]]
,沿着同一条线,依此类推...
但是它可以使用类型类或 Haskell 的其他功能使用一个运算符(如 Matlab 能够做到的那样)来完成吗?
我知道这是合成糖,但如果可能的话它会很甜。
-- 更新--
我发现使用 (Num a)
可能有问题正如@DanielWagner 的回答中所解释的,最好为 Integer, Double
单独定义它。等等。
仅作记录,我只是按照建议尝试了:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
class Additive a where (<+>) :: a -> a -> a
instance Num a => Additive a where (<+>) = (+)
instance Additive a => Additive [a] where (<+>) = zipWith (<+>)
或者
{-# LANGUAGE DefaultSignatures #-}
class Additive a where
(<+>) :: a -> a -> a
default (<+>) :: Num a => a -> a -> a
(<+>) = (+)
无论哪种情况,加载 .hs
时都会出错文件或评估时 [[1,2]] <+> [[3,4]]
.
是的,这是可能的:
class Additive a where (<+>) :: a -> a -> a
instance Additive Integer where (<+>) = (+)
instance Additive a => Additive [a] where (<+>) = zipWith (<+>)
你在 ghci 中的三个测试用例:
*Main> 1 <+> 2
3
*Main> [1] <+> [2]
[3]
*Main> [[1]] <+> [[2]]
[[3]]
如果你想要很多 (<+>) = (+)
的实例,您可以使用 DefaultSignatures
将其设为默认实现:
{-# LANGUAGE DefaultSignatures #-}
class Additive a where
(<+>) :: a -> a -> a
default (<+>) :: Num a => a -> a -> a
(<+>) = (+)
优点是有些实例可以很短,例如
instance Additive Integer
instance Additive Int
instance Additive Double
instance Additive Float
将按预期工作,无需任何额外的方法定义。
我是一名优秀的程序员,十分优秀!