【发布时间】:2017-09-21 15:58:59
【问题描述】:
我是 Haskell 的初学者,正在尝试学习类型类和类型。我有以下示例(它代表了我正在研究的代数中的一个真正问题),其中我定义了一个仅包装 Num 实例的类型,以及一个定义二进制操作baz 的类型类。
newtype Foo i = B i deriving (Eq, Ord, Show)
class Bar k where
baz :: k -> k -> k
instance Num k => Bar (Foo k) where
baz (B a) (B b) = B (f a b)
f :: Num a => a -> a -> a
f a b = a + b
当将Bar 定义为它的一个实例时,我意识到我希望能够使用类型“改变”函数f。明确一点:我想提供一个函数f :: Num a => a -> a -> a 并返回一个新类型Foo,它是Bar 的一个实例。假设我想这样做 5、10 次,唯一的区别是不同的功能 f。上面的代码我当然可以复制粘贴,不过不知道有没有别的办法呢?
在我看来,我把事情搞糊涂了。在 Haskell 中做这样的事情的最好方法是什么?这是一个很好的设计选择吗?我在想什么是对的/错的,为什么?
编辑:我意识到一个具体的例子可能有助于使问题更清楚(请注意,它可能看起来很复杂,我无法简化代码。上面的问题包含我认为的相同信息):我感兴趣的 typeclass 是来自库 HaskellForMaths 的 Algebra k v:
class Algebra k b where
unit :: k -> Vect k b
mult :: Vect k (Tensor b b) -> Vect k b
这里k 是一个域(一种数学结构,例如实数或复数),而v 是向量空间中的基选择。我想像这样使用它
newtype Basis i = T i deriving (Eq, Ord, Show)
type Expression k = Vect k (Basis Int)
instance Algebra k Basis where
unit x = x *> return I
mult = linear mult'
where mult' (T x ,T y) = comm x y
where comm a b = sum $ map (\c -> structure a b c *> t c) [0..n]
t :: Int -> Expression k
t a = return (T a)
然后随意更改地图structure。这里T 类型只是编写抽象基础元素T 1, T 2, ... 的一种便捷方式。我想这样做的原因是根据其结构常数的代数的标准数学定义(此处:structure)。总结一下:我希望能够改变函数f(最好不是在编译时?)并取回代数。这可能是一个糟糕的设计决策:如果是,为什么?
【问题讨论】:
-
你能提供一个你打算如何使用它的例子吗?和/或可能提供第二个实例以明确冗余?更具描述性的名称也可能会有所帮助。
Foo可以是Functor/Applicative使用类似f <$> B a <*> B b的东西 -
Bar类型类看起来像Semigroup。如果二元运算也有标识,则可能是Monoid。 -
你能完全跳过 newtype 和 typeclass 并直接传递
(+)(或任何其他你想要的函数)吗? -
我提供了一个我打算如何使用它的例子!我现在时间不多,稍后会尝试澄清更多,同时感谢所有回复!如果我可以跳过类型类、monoid 属性等,我将需要一些时间以有意义的方式回答。
标签: haskell types typeclass newtype