2016-09-16 79 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.