如何解决带数据的实例函子
我是 Haskell 的新手,但我实现了这个:
data Triple = T Double Double Double
instance Functor Triple where
fmap f (T a b c) = T (f a) (f b) (f c)
然后我试图使 Triple
成为 Functor
但是
我收到这条消息:
**error:
• Expected kind ‘* -> *’,but ‘Triple’ has kind ‘*’
• In the first argument of ‘Functor’,namely ‘Triple’
In the instance declaration for ‘Functor Triple**’
所以我的问题是,我真的必须将数据构造函数更改为
data Triple a = a a a
???
这是我的解决方案,但有更好的解决方案吗?
解决方法
是的,你需要一个 * -> *
类型的 Functor。
它必须是这样的,因为 fmap
的类型是 fmap :: (a -> b) -> f a -> f b
- 所以你可以看到 f
被应用到类型参数 { {1}} 在那里。
所以是的,这行得通:
a
data Triple a = T a a a
instance Functor Triple where
fmap f (T a b c) = T (f a) (f b) (f c)
意味着您需要一个等待 Type 并返回 Type 的类型构造函数。
例如:
-
* -> *
有种类Double
-
*
(此处)有种类Triple
-
* -> *
再次对Triple Double
友好
它就像是类型级别的柯里化函数;)
你可以为你的 *
写这样的东西:
Triple
也许这对你来说已经足够了。
,这是我的解决方案,但有更好的解决方案吗?
嗯,这取决于您所说的“更好”是什么意思。 Triple a
很有意义,如果它不是真正针对 Double
。
如果您有充分的理由对 Double
进行硬编码,那么您始终可以创建一个专用函数来映射此数据类型,例如 Carsten 解决方案中的 tripleMap
。 There is 也是此类操作的广泛使用的类型类:
{-# LANGUAGE TypeFamilies #-}
import Data.MonoTraversable
type instance Element Triple = Double
instance MonoFunctor Triple where
omap f (T a b c) = T (f a) (f b) (f c)
还要考虑将任意函数映射到您的类型上是否有意义。也许你真正想要的是这个?
import Data.AdditiveGroup
import Data.VectorSpace
data ℝ³ = ℝ³ Double Double Double
instance AdditiveGroup ℝ³ where
zeroV = ℝ³ 0 0 0
ℝ³ x y z ^+^ ℝ³ ξ υ ζ = ℝ³ (x+ξ) (y+υ) (z+ζ)
negateV (ℝ³ x y z) = ℝ³ (-x) (-y) (-z)
instance VectorSpace ℝ³ where
type Scalar ℝ³ = Double
μ *^ ℝ³ x y z = ℝ³ (μ*x) (μ*y) (μ*z)
,
答案是肯定的,你需要定义
data Triple a = T a a a
instance Functor Triple where
fmap f (T x y z) = T (f x) (f y) (f z)
我使用 x,y,z
强调这些不是类型,而是值。
Triple a
是类型。它的值包含三个相同类型的值,a
,以每种特定情况下的值为准,例如 Double
或其他。
由于fmap :: (a -> b) -> f a -> f b
,在Triple
的情况下是fmap :: (a -> b) -> Triple a -> Triple b
,Triple b
类型的值在其中携带三个相同类型的值,{{1} }.
因此,我们必须在 b
等中转换三个中的每一个
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。