2015-10-19 36 views
3

我正在將GHC/Arr.hs移植到Frege中。可以函數實例聲明爲函數的其他類型限制

數組定義:

data Array i e = Array{u,l::i,n::Int,elems::(JArray e)} 

有功能:

amap :: (Ix i, ArrayElem e) => (a -> b) -> Array i a -> Array i b 

現在,我不知道如何定義Functor實例,因爲

instance (Ix i) => Functor (Array i) where 
    fmap = amap 

但編譯器抱怨推斷的類型比預期更受限制,看起來確實如此。我可以使Array作爲函數ArrayElem -> ArrayElem的函數嗎?

回答

3

不,這是不可能的。

如果您的基於JArray並且想要一個仿函數實例,則不得使用產生ArrayElem(或任何其他附加)上下文的任何函數。

另一種說法是,你不能在類型安全的java數組上使用Array,但必須處理類型爲Object[]的java數組。因爲,毫無疑問地指出,ArrayElem類型類僅僅是能夠在創建java數組時提供正確的java類型的技巧。當然,這對於與Java接口以及出於性能原因而言非常重要。

請注意,類型安全Java數組存在另一個問題。假設我們想要製作一個Double的數組(但對於任何其他元素類型,同樣的理由也適用)。 AFAIK,Haskell要求數組元素必須是懶惰的。因此,我們實際上不能使用java類型double[](其中JArray Double將作爲Frege對應物)來對它進行建模。因爲,如果我們要這樣做,每個數組元素只要設置就必須進行評估。

出於這個原因,我建議你用一些普通的自定義數組元素的類型,比如

data AElem a = AE() a 
mkAE = A() 
unAE (AE _ x) = x 
derive ArrayElement AElem 

,改變你的定義:

data Array i e = Array{u,l::i,n::Int,elems::(JArray (AElem e))} 

現在,你的仿函數實例可以寫,因爲ArrayElem約束不會出現,因爲當您訪問elems數組時,編譯器知道您有AElem元素,並且可以並將提供正確的實例。

此外,AElem的建設和AElem小號用法實際的數組元素確實上的實際值未強加嚴格。

不用說,Array模塊的用戶不應該(需要)知道那些實現細節,即AElem類型。

+0

謝謝! 只是「派生ArrayElem AElem」應該是'驅動ArrayElement AElem'。 ArrayElem不是「可派生的」。 –

+0

是的,對,我總是混淆它。 – Ingo