要创建描述为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)
答案 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
应该能够将类型构造函数的类型参数更改为其他任何内容 - 请注意a
和b
在{ {1}}的类型签名完全是任意的。如果你有......
fmap
...然后,data T
= ConsInt Int
| ConsString String
| ConsChar Char
值不能包含T
,Int
或String
以外的任何内容,因此要求它为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
的定义不处理mult2
和ConsString
个案例,忽略这一点几乎总是一个坏主意。解决这个问题的明显方法是为其他构造函数添加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(这两个问题碰巧提到新类型并不重要)。