如何将内嵌的自定义数据类型对象相乘?

时间:2018-04-01 04:04:05

标签: haskell

要创建描述为in this Haskell Wiki page的基于数据类型的异构列表,可以将数据类型T定义为:

data T = ConsInt    Int
       | ConsString String
       | ConsChar   Char

然后使用:

创建一个对象
ConsInt 200

然后如何乘以对象T?如果我们使用类型构造函数Maybe,如:

Just 200

我们可以使用fmap (*2) (Just 200)将其乘以2并输出Just 400

然而,

执行fmap (*2) (ConsInt 200)并不起作用。 (我猜测因为T不是类型构造函数而是数据类型

然后,如何将T对象内联,而不必手动定义函数:

mult2 :: T -> T
mult2 (ConsInt r) = ConsInt ((*2) r)

或者如何使用比这更简单的匿名函数:

(\(ConsInt r) -> ConsInt ((*2) r)) (ConsInt 200)

Runnable example

1 个答案:

答案 0 :(得分:4)

  然而,

执行fmap (*2) (ConsInt 200)不起作用。 (我猜是因为T不是类型构造函数而是数据类型

这是部分原因。 fmap (*2) (Just 200)有效,因为Maybe是一个类型构造函数,它是Functor的一个实例:

GHCi> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
GHCi> :set -XTypeApplications
GHCi> :t fmap @Maybe
fmap @Maybe :: (a -> b) -> Maybe a -> Maybe b

Functor必须是类型构造函数,它接受一个类型并生成另一个类型(也就是说,它们必须具有类型* -> *):

GHCi> :k Functor
Functor :: (* -> *) -> Constraint

这是因为,粗略地说,fmap应该能够将类型构造函数的类型参数更改为其他任何内容 - 请注意ab在{ {1}}的类型签名完全是任意的。如果你有......

fmap

...然后,data T = ConsInt Int | ConsString String | ConsChar Char 值不能包含TIntString以外的任何内容,因此要求它为Char无法满足。如果你真的想坚持让它成为Functor,那么一个行动方案就是在Functor所在的地方戳一个洞:

Int

虽然在其他情况下这可能是一次有用的重构,但我很确定你不会在这里做到这一点。

  

然后,如何将-- You can actually write a Functor instance for this: data T a = ConsStuff a | ConsString String | ConsChar Char 对象内联,而不必手动定义函数[...]或者如何使用比[...]

请注意,如果您要T T个实例,Functor的实现将与您在此处思考的功能一样复杂。 (我忽略了这样一个事实:由于fmap扩展,你实际上从来没有必要写一个DeriveFunctor实例,但除了这一点之外,这是一种。)为了比较,这是the Functor instance for Maybe看起来像什么:

Functor

如果您想要比instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a) 更通用的内容,则可以定义mult2 :: T -> T。顺便说一句,请注意您对mapConsInt :: (Int -> Int) -> T -> T的定义不处理mult2ConsString个案例,忽略这一点几乎总是一个坏主意。解决这个问题的明显方法是为其他构造函数添加do-nothing案例(就像在ConsChar fmap中所做的那样);但是,根据您要执行的操作,您可能更愿意让函数返回Maybe而不是Maybe T(在这种情况下,请注意以“map”开头的名称不会是像以前一样合适。)

P.S。:正确实现的T非常类似于mapConsInt :: (Int -> Int) -> T -> T,但它仅限于特定的函数类型。事实上,只要我们清楚它是一个不是fmap的仿函数,说我们在这里处理仿函数并不是错误的。 (由于上面讨论的原因,它不是Functor,即因为它只能映射Functor函数。)关于如何处理这种情况的一些考虑(以及指向你可能想要的东西的指针)要知道某些情况),请参阅What is the idiomatic way to build functions over newtypes ("wrapped types") in Haskell?Haskell: Functor instance for newtype(这两个问题碰巧提到新类型并不重要)。