fmap 可变参数函数
fmap over variable argument function
我想在可变参数函数上定义 fmap
:
type family VarArg (args :: [*]) e where
VarArg '[] e = e
VarArg (a ': as) e = a -> VarArg as e
mapVarArg :: forall args e e'
. (e -> e') -> VarArg args e -> VarArg args e'
mapVarArg f = _
这是我找到的最接近的解决方案:
mapVarArg :: forall args e e' . VarArgIso args
=> (e -> e') -> VarArg args e -> VarArg args e'
mapVarArg f = (^. Lens.from varArgIso) . fmap f . (^. varArgIso @args)
data VarArgD (args :: [*]) e where
DNil :: e -> VarArgD '[] e
DCons :: (a -> VarArgD as e) -> VarArgD (a ': as) e
class VarArgIso (args :: [*]) where
varArgIso :: Iso' (VarArg args e) (VarArgD args e)
instance VarArgIso '[] where
varArgIso = iso DNil (\(DNil x) -> x)
instance VarArgIso as => VarArgIso (a ': as) where
varArgIso = iso (\f -> DCons ((^. varArgIso) . f)) (\(DCons f) -> ((^. Lens.from varArgIso) . f))
instance Functor (VarArgD args) where
fmap f (DNil a) = DNil (f a)
fmap f (DCons g) = DCons (fmap f . g)
是否有更简单的解决方案,或者没有额外 VarArgIso
约束的任何解决方案?
我认为如果没有额外的 class 约束,非模板解决方案是不可能的。有一个简单且可能有效的重叠实例实现:
class VarArg a b c d where
mapVarArg :: (a -> b) -> c -> d
instance (a ~ c, b ~ d) => VarArg a b c d where
mapVarArg = id
instance {-# overlapping #-} (VarArg a b c2 d2, c1 ~ d1) =>
VarArg a b (c1 -> c2) (d1 -> d2) where
mapVarArg f g = mapVarArg f . g
如果将 overlapping
替换为 incoherent
,它通常也适用于 polymorphic/constrained 函数作为参数:
> mapVarArg (+100) (+) 0 0
100
但是,对于 incoherent
实例,部分应用的 mapVarArg
-s 往往具有不可用的推断类型。
> let foo = mapVarArg (+100) (+)
> :t foo
foo :: (Num (a -> a -> a), Num a) => a -> a -> a
我想在可变参数函数上定义 fmap
:
type family VarArg (args :: [*]) e where
VarArg '[] e = e
VarArg (a ': as) e = a -> VarArg as e
mapVarArg :: forall args e e'
. (e -> e') -> VarArg args e -> VarArg args e'
mapVarArg f = _
这是我找到的最接近的解决方案:
mapVarArg :: forall args e e' . VarArgIso args
=> (e -> e') -> VarArg args e -> VarArg args e'
mapVarArg f = (^. Lens.from varArgIso) . fmap f . (^. varArgIso @args)
data VarArgD (args :: [*]) e where
DNil :: e -> VarArgD '[] e
DCons :: (a -> VarArgD as e) -> VarArgD (a ': as) e
class VarArgIso (args :: [*]) where
varArgIso :: Iso' (VarArg args e) (VarArgD args e)
instance VarArgIso '[] where
varArgIso = iso DNil (\(DNil x) -> x)
instance VarArgIso as => VarArgIso (a ': as) where
varArgIso = iso (\f -> DCons ((^. varArgIso) . f)) (\(DCons f) -> ((^. Lens.from varArgIso) . f))
instance Functor (VarArgD args) where
fmap f (DNil a) = DNil (f a)
fmap f (DCons g) = DCons (fmap f . g)
是否有更简单的解决方案,或者没有额外 VarArgIso
约束的任何解决方案?
我认为如果没有额外的 class 约束,非模板解决方案是不可能的。有一个简单且可能有效的重叠实例实现:
class VarArg a b c d where
mapVarArg :: (a -> b) -> c -> d
instance (a ~ c, b ~ d) => VarArg a b c d where
mapVarArg = id
instance {-# overlapping #-} (VarArg a b c2 d2, c1 ~ d1) =>
VarArg a b (c1 -> c2) (d1 -> d2) where
mapVarArg f g = mapVarArg f . g
如果将 overlapping
替换为 incoherent
,它通常也适用于 polymorphic/constrained 函数作为参数:
> mapVarArg (+100) (+) 0 0
100
但是,对于 incoherent
实例,部分应用的 mapVarArg
-s 往往具有不可用的推断类型。
> let foo = mapVarArg (+100) (+)
> :t foo
foo :: (Num (a -> a -> a), Num a) => a -> a -> a