如何在不求助于newtype的情况下使(a, a)成为Functor
基本上,我希望它是这样工作的:
instance Functor (a, a) where
fmap f (x, y) = (f x, f y)但当然,这不是一种合法的表达方式:
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `(a, a)' has kind `*'
In the instance declaration for `Functor (a, a)'我真正想要的是一个像这样的类型级函数:\a -> (a, a) (无效语法)。那么,也许是一个类型别名?
type V2 a = (a, a)
instance Functor V2 where
fmap f (x, y) = (f x, f y)我本以为这能行得通,但事实并非如此。首先,我收到这样的抱怨:
Illegal instance declaration for `Functor V2'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Functor V2'如果我按照建议添加了TypeSynonymInstances扩展,我会得到一个新的错误:
Type synonym `V2' should have 1 argument, but has been given 0
In the instance declaration for `Functor V2'好了,对了,这就是问题所在!V2拥有一个Functor实例所需要的友好的* -> *。好吧,好吧,我可以使用这样的newtype:
newtype V2 a = V2 (a, a)
instance Functor V2 where
fmap f (V2 (x, y)) = V2 (f x, f y)但现在,我必须在代码中自由地使用V2,而不是仅仅处理简单的元组,这有点违背了将其变成Functor的意义;在这一点上,我不妨将自己的函数设为vmap :: (a -> b) -> (a, a) -> (b, b)。
那么,有没有什么方法可以很好地做到这一点,也就是不使用newtype
发布于 2011-01-27 13:46:35
正如其他人所说,如果不求助于新类型或数据声明,就无法做到这一点。但是,你有没有看过Control.Arrow?其中许多函数对元组非常有用,例如:
vmap :: (a -> b) -> (a,a) -> (b,b)
vmap f = f *** f发布于 2011-01-27 12:13:58
你可以声明
instance Functor ((,) a) where
...然而,这并不限制您的元素对中的第一个元素,并且fmap只会作用于第二个元素。
问题是元组并不强制两个元素的类型之间的关系。
如果你不需要newtype装饰器,你可以自己做一个新的类型:
data Pair a = P a a
instance Functor Pair where
...它将比元组周围的newtype更容易使用。
发布于 2017-12-08 20:12:14
使用singletons,您可以为废弃的符号定义Functor类型类(Type ~> Type而不是Type -> Type)
{-# Language ExplicitNamespaces, TypeApplications, TypeOperators, KindSignatures, ScopedTypeVariables, DataKinds, TypeInType, TypeFamilies, AllowAmbiguousTypes, InstanceSigs #-}
import Data.Kind (Type)
import Data.Singletons (type (~>), Apply)
class Functor' (f :: Type ~> Type) where
fmap' :: (a -> a') -> (Apply f a -> Apply f a')
data Dup :: Type ~> Type
type instance Dup `Apply` a = (a, a)
instance Functor' Dup where
fmap' :: (a -> a') -> ((a, a) -> (a', a'))
fmap' f (a1, a2) = (f a1, f a2)这将自动提供一个Prelude.Functor实例
newtype f $ a = App (Apply f a)
instance Functor' f => Functor (($) f) where
fmap :: (a -> a') -> (f $ a -> f $ a')
fmap f (App fa) = App (fmap' @f f fa) https://stackoverflow.com/questions/4812633
复制相似问题