2015-07-11 67 views
3

我一直在試圖獲得一些編譯代碼。這意味着要採取HList,提取出字符串並將它們連接在一起。HLists中的修復類型推斷


{-# LANGUAGE RankNTypes #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE TypeSynonymInstances #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 

module Lib 
    (y 
    ) where 

import Data.HList 

data HConcat2 = HConcat2 
instance ApplyAB HConcat2 (String, String) String where 
    applyAB _ (a,b) = a ++ b 
instance ApplyAB HConcat2 (Int, String) String where 
    applyAB _ (_,a) = a 

x :: HList '[Int, String, Int, String] 
x = 3 .*. "Hello" .*. 4 .*. " World" .*. HNil 

y :: String 
y = hFoldr HConcat2 "Result: " x 

不幸的是,當我嘗試編譯這一點,讓我

 
    No instance for (ApplyAB HConcat2 ([Char], [Char]) r2) 
     arising from a use of ‘hFoldr’ 
    The type variable ‘r2’ is ambiguous 
    Note: there is a potential instance available: 
     instance ApplyAB HConcat2 (String, String) String 
     -- Defined at src/Web/Rusalka/Condition.hs:274:10 
    In the expression: hFoldr HConcat2 "Result: " x 
    In an equation for ‘y’: y = hFoldr HConcat2 "Result: " x 

如何說服它使用我已經聲明瞭實例?

回答

2

ApplyAB類沒有函數依賴關係,所以當GHC試圖選擇一個實例時,輸入類型不會確定結果類型。在這種情況下,這會導致hFoldr鏈中的所有中間類型變得不明確,而GHC不知道要選擇哪些實例。

爲了解決這個問題,你可以使用一個小技巧,讓您保持結果的實例的頭型完全通用的,並使用一個等式~約束來限制它 GHC選擇了實例(只有頭部的一個實例用於選擇)。

如果您在GHCi中做:i ApplyAB,您會注意到幾個預定義的實例使用了這樣的等式約束。

使用這個(和添加TypeFamilies)使你的代碼工作對我來說:

{-# LANGUAGE RankNTypes #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE TypeSynonymInstances #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies #-} 

module Lib 
    (y 
    ) where 

import Data.HList 

data HConcat2 = HConcat2 
instance s ~ String => ApplyAB HConcat2 (String, String) s where 
    applyAB _ (a,b) = a ++ b 
instance s ~ String => ApplyAB HConcat2 (Int, String) s where 
    applyAB _ (_,a) = a 

x :: HList '[Int, String, Int, String] 
x = 3 .*. "Hello" .*. 4 .*. " World" .*. HNil 

y :: String 
y = hFoldr HConcat2 "Result: " x