一般来说,是的。通常这是可取的,因为它允许您删除您不希望人们访问的功能。例如,给用户[Double]
让他们计算长度并将其作为链接列表进行检查,而当且仅当您认为这是一个好主意时,您才newtype Vector = Vector [Double]
可以公开。vectorLength
但这不是手头的问题。您立即希望能够对您的Vector
类型进行操作,而无需重新定义您能想到的每一个有用的功能。幸运的是,有很多方法可以解决这个问题。
您可以定义Vector
为type
同义词而不是新的具体类型。这让 Haskell 可以透明地解释Vector
为[Double]
并自动使用完整的列表函数
type Vector = [Double]
vectorSum :: Vector -> Double
vectorSum = sum
你可以,尽管你试图避免它,也可以vectorSum
直接写你自己的。
vectorSum :: Vector -> Double
vectorSum (Vector list) = sum list
一般来说,它在实际代码中看起来有点不同,因为人们倾向于滥用记录语法来为Vector
data Vector = Vector { unVector :: [Double] }
vectorSum :: Vector -> Double
vectorSum = sum . unVector
manySums :: [Double]
manySums = map (\v -> sum (unVector v)) makeLotsOfVectors
您可以定义Vector
为Foldable
. Foldable
是一个类型类,是 Haskell 实现多态性的主要机制。特别是,您说类型t
是一个实例,Foldable
如果您可以将其视为包含可以“粉碎”在一起的特定顺序的元素。这几乎描述了 aVector
和 a sum
,所以
import Prelude hiding (foldl)
import Data.Foldable (Foldable, foldl, foldMap)
data Vector a = Vector [a] -- note that the type is parametric, this is
-- required for Foldable
foldableSum :: (Foldable t) => t Double -> Double
foldableSum = foldl (+) 0
instance Foldable Vector where
foldMap f (Vector list) = foldMap f list -- it just inherits from the
-- Foldable [] instance
vectorSum :: Vector Double -> Double
vectorSum = foldableSum
您还可以使用 GHC Haskell 调用的一种非常方便的机制GeneralizedNewtypeDeriving
来使这些繁琐的实例自动发生。为此,我们必须注意它与Vector
---它实际上只是它的一个新名称。这意味着我们可以使用而不是.[]
newtype
data
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Vector a = Vector [a] deriving ( Foldable )
vectorSum :: Vector Double -> Double
vectorSum = foldl (+) 0
有趣的是,GHC Haskell 还有一个扩展,Foldable
即使您没有新类型,也可以派生。GeneralizedNewtypeDeriving
更强大,但Foldable
具体来说我们不需要使用它。
{-# LANGUAGE DeriveFoldable #-}
data Vector a = Vector [a]
vectorSum :: Vector Double -> Double
vectorSum = foldl (+) 0
还有其他人提到的非常强大的vector
库,它可以完成所有这些以及更多。