修复 HList 中的类型推断
Fixing type inference in HLists
我一直在尝试编译一些代码。它的意思是取一个HList
,提取字符串并将它们连接在一起。
{-# 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
如何说服它使用我声明的实例?
ApplyAB
class 没有函数依赖性,因此当 GHC 尝试 select 一个实例时,输入类型不决定结果类型。在这种情况下,这会导致 hFoldr
链中的所有中间类型变得不明确,并且 GHC 不知道哪些实例到 select.
要解决这个问题,您可以使用一个技巧,将结果类型完全通用地保留在实例的头部,并使用等式 ~
约束来限制它 after GHC 已 select 编辑了实例(只有实例的头部用于 selection)。
如果你在 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
我一直在尝试编译一些代码。它的意思是取一个HList
,提取字符串并将它们连接在一起。
{-# 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
如何说服它使用我声明的实例?
ApplyAB
class 没有函数依赖性,因此当 GHC 尝试 select 一个实例时,输入类型不决定结果类型。在这种情况下,这会导致 hFoldr
链中的所有中间类型变得不明确,并且 GHC 不知道哪些实例到 select.
要解决这个问题,您可以使用一个技巧,将结果类型完全通用地保留在实例的头部,并使用等式 ~
约束来限制它 after GHC 已 select 编辑了实例(只有实例的头部用于 selection)。
如果你在 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