我正在尝试将元组转换为HList.Record
并且有一些非常奇怪的东西。
我创建了一个ToRecord
类,其中压缩一组事物和一组标签到记录。
一切都在编译,但实例似乎消失了。当我尝试使用它们时,GHC抱怨我要求的实例不存在。
{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
-- standard
import GHC.TypeLits (Symbol)
-- third-party
import Data.HList.FakePrelude
import Data.HList.Record
import Data.HList.Labelable
-- local
-- * Tuples <-> Records Conversion
class ToRecord a b where
type Result a b :: *
toRecord :: a -> b -> Result a b -- Result a b
instance ToRecord (Label t1, Label t2) (v1, v2) where
type Result (Label t1, Label t2) (v1, v2) = Record '[Tagged (t1) v1, Tagged (t2) v2]
toRecord (t1, t2) (v1, v2) = t1 .=. v1 .*. t2 .=. v2 .*. emptyRecord
instance ToRecord (Label t1, Label t2, Label t3) (v1, v2, v3) where
type Result (Label t1, Label t2, Label t3) (v1, v2, v3) =
Record '[Tagged (t1) v1, Tagged (t2) v2, Tagged t3 v3]
toRecord (t1, t2, t3) (v1, v2, v3) = t1 .=. v1 .*. t2 .=. v2 .*. t3 .=. v3 .*. emptyRecord
-- dummy instance to check GHC behavior
instance ToRecord Char Integer where
type Result Char Integer = (Char, Integer)
toRecord c i = (c, i)
value = Label :: Label "value"
name = Label :: Label "name"
test = toRecord (value, name) (5 :: Int, "age")
错误讯息:
Utils.hs:34:8:
No instance for (ToRecord
(Label Symbol "value", Label Symbol "name") (Int, [Char]))
arising from a use of `toRecord'
Possible fix:
add an instance declaration for
(ToRecord
(Label Symbol "value", Label Symbol "name") (Int, [Char]))
In the expression: toRecord (value, name) (5 :: Int, "age")
In an equation for `test':
test = toRecord (value, name) (5 :: Int, "age")
此外,如果删除test
行并将文件加载到GHC中。实例丢失(使用:i ToRecord
),只显示虚拟的ToRecod Char Integer
。
Utils Database.Harehouse.SQLFragment>:i ToRecord
class ToRecord a b where
type family Result a b :: *
toRecord :: a -> b -> Result a b
-- Defined at Database/Harehouse/Utils.hs:15:7
instance ToRecord Char Integer
-- Defined at Database/Harehouse/Utils.hs:27:10
任何想法(我使用的是GHC 7.6.3)?
答案 0 :(得分:3)
错误非常明确:编译器推断实例必须是ToRecord (Label Symbol "value", Label Symbol "name") (Int, [Char])
,但不存在此类实例。您隐式编写的实例具有另一个参数:参数的类型。在这种情况下,您所拥有的是ToRecord (Label (t1 :: *), Label (t2 :: *)) (v1, v2)
- 除非您使用PolyKinds
,否则所有多态种类都会成为*
。例如:
l0 = Label :: Label Int
l1 = Label :: Label Bool
test = toRecord (l0, l1) (5 :: Int, "age")
编译就好了。如果您打开PolyKinds
,则可以写
instance ToRecord (Label (t1 :: k), Label (t2 :: k)) (v1, v2) where
然后您的示例将起作用:
>toRecord (value, name) (5 :: Int, "age")
Record{value=5,name="age"}
我无法复制这个问题而某些实例没有显示出来。
澄清言论:
也许我不应该说它很清楚。类型类型的类型是构造函数的参数。 Label
实际上有两个参数: type 参数和type参数的种。首先写入kind参数 - 因此,您有value :: Label Symbol "value"
(符号是一种字符串类型文字)。当然,你不能这样写,但这就是GHC打印它的方式。
种类可以像类型一样推断。默认情况下,推断的类型将为*
。在您的代码中,t1
中的t2
和ToRecord (Label t1, Label t2) (v1, v2)
类型为*
。因此,Label ("value" :: Symbol)
和Label (t1 :: *)
无法统一。
t1 :: k
和t1 :: Symbol
都可以像(f :: Integral a => a -> a) (1 :: Int)
和(f :: Int -> Int) (1 :: Int)
一样工作。您需要KindSignatures
扩展名才能写t1 :: Symbol
,但KindSignatures
和DataKinds
隐含PolyKinds
。