2016-09-16 76 views
3

考虑下面的Haskell代码:如何强制仿函数应用于强制转换参数

import Data.Coerce 

newtype Decorated s a = Decorated a 

fancyFunction :: Ctx s => f (Decorated s a) -> r 
fancyFunction = ... 

instance Ctx s => SomeClass (Decorated s a) 

myFunction :: Functor f => f a -> r 
myFunction = fancyFunction . fmap coerce 

我想用coerce更换fmap coerce使myFunction更快。理由是coerce的行为类似于id,其中一个函子法则是fmap id = id

我可以看到这样做的唯一方法是将Coercible (f a) (f (Decorated s a))添加到上下文中,但它指的是s不会引用到其他任何地方。更糟糕的是,如果a被绑定为通用类型,我无法表达约束。有没有一个限制,我可以用f来表示,只允许我用coerce来转换f af (Decorated s a)

这是编译器自己从f是一个仿函数算出的东西吗?如果是这样,它是否也适用于双通道,可穿越性和可比性?

+0

'myFunction'已经不能编译,因为类型's'没有提到在函数的类型(如你所指出的那样),所以'CTX s'从'fancyFunction'产生会导致一个模糊的类型错误(即使'fancyFunction。undefined'也会产生这样的错误)。在任何情况下,它都会看到你想要一个函数'(Functor f,Coercible ab)=> fa - > fb',这在操作上就是身份,在这种情况下你可能会对[通用函数]感兴趣(https://hackage.haskell。 org/package/profunctors-5.2/docs/Data-Profunctor-Unsafe.html#v:-35-。) - 一般使用'不安全'的操作,但GHC会告诉你..“ – user2407038

+1

”注:我们不知道什么角色参数到\'f';我们必须假定角色是名义上的“,如果您修复了不相关的模糊类型错误(例如通过移除'Ctx s'约束)。没有办法谈论类型变量的作用 - 这是一个已知的限制。 – user2407038

+1

我很确定没有办法解决这个问题。问题是你想做什么可以或不可以做什么取决于任何'f'的角色。 [This](https://ghc.haskell.org/trac/ghc/ticket/9123)票证更详细。 [Here](https://github.com/ekmett/roles/blob/master/src/Data/Roles.hs)是Edward Kmett的替代方法之一。 – Alec

回答

4

不幸的是,Coercible (f a) (f (Decorated s a))真的是你在给定GHC当前状态的约束下想要的。现在,其他sa没有出现在其他地方的事实并不好 - 这意味着GHC不会知道如何处理它们(它们是模棱两可的)!我不会成...


根据送入类型构造f类型参数的roleCoercible a b可能会或可能不会暗示Coercible (f a) (f b)。在这种情况下,我们希望这个角色是名义上的 - 但是没有(至少)有一种方式来表达这种约束。为了解释我的意思,考虑以下两个数据定义:

{-# LANGUAGE TypeFamilies #-} 
import Data.Coerce 

-- type role of `a` is "representational" 
data Data1 a = Data1 a 

-- type role of `a` is "nominal" 
data Data2 a = Data2 (TypeFunction a) 
type family TypeFunction x where 
    TypeFunction Bool = Char 
    TypeFunction _ =() 

然后,当它是真实的Coercible a b需要Coercible (Data1 a) (Data1 b),它意味着Coercible (Data2 a) (Data2 b)。为了使这个混凝土,加载在GHCI上面,然后尝试:

ghci> newtype MyInt = My Int 
ghci> let c1 = coerce :: (Data1 MyInt) -> (Data1 Int) 
ghci> let c2 = coerce :: (Data2 MyInt) -> (Data2 Int) -- This doesn't work! 

不幸的是,执行一个类型变量的作用是代表性的没有内置的基于约束的方式。您可以为此创建自己的类,如Edward Kmett has done,但GHC不会像Coercible的类实例那样自动创建这些类中的某些类的实例。

这导致this TRAC票,他们讨论与像生成Coercible可能有事情像

instance (Representational f, Coercible a b) => Coercible (f a) (f b) 

如果今天实际上是一个东西,实例的类Representational f的可能性,所有你需要在你的约束将是Representational f。此外,正如理查德艾森伯格在票上所说的,我们真的应该能够弄清楚f a中的a对于任何合理的函子f都具有代表性。那么,我们可能甚至不需要在Functor f之上的任何约束,因为Representational可能是Functor的超类。

Here is a good discussion of the current limitations of roles.