随着最近关于HaskellDB的帖子的发布,我有动力再次研究HList。因为我们现在在GHC中有了-XDataKinds,实际上有一个异构列表的例子,所以我想研究一下HLists在DataKinds中是什么样子的。到目前为止,我有以下几点:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
import Data.Tagged
data Record :: [*] -> * where
RNil :: Record '[]
(:*:) :: Tagged f (FieldV f) -> Record t -> Record (f ': t)
type family FieldV a :: *
emptyRecord = RNil
(=:) :: (v ~ FieldV f) => f -> v -> Tagged f v
f =: v = Tagged v
class HasField x xs where
(=?) :: Record xs -> x -> FieldV x
instance HasField x (x ': xs) where
(Tagged v :*: _) =? _ = v
instance HasField x xs => HasField x (a ': xs) where
(_ :*: r) =? f = r =? f
--------------------------------------------------------------------------------
data EmployeeName = EmployeeName
type instance FieldV EmployeeName = String
data EmployeeID = EmployeeID
type instance FieldV EmployeeID = Int
employee = (EmployeeName =: "James")
:*: ((EmployeeID =: 5) :*: RNil)
employeeName = employee =? EmployeeName
employeeId = employee =? EmployeeID这可以像预期的那样工作,但我在这个项目中的目标是尝试尽可能多地不使用类型类。所以这里有两个问题。首先,有没有可能在没有类型类的情况下编写(=?) (记录字段访问器函数)?如果不是,是否可以在不重叠实例的情况下编写?
我想我的第一个问题是不可能的,但第二个问题可能是可能的。我很想听听人们的想法!
发布于 2012-08-26 17:43:34
我认为这两个问题的答案都是一个合格的no。您不能简单地使用以下形式的类型函数
type family TypeEq a b :: Bool
type instance TypeEq a a = True
type instance TypeEq a b = False这本质上就是OverlappingInstances给你的。奥列格已经提出了一种使用类型级TypeReps的替代机制,但我们还没有。这个答案是有限制的,因为您确实有丑陋的“解决方案”,比如使用typeable
{-# LANGUAGE DataKinds, GADTs, DeriveDataTypeable, TypeFamilies, TypeOperators #-}
import Data.Typeable
type family FieldV a :: *
data FieldOf f where
FieldOf :: FieldV f -> FieldOf f
(=:) :: f -> FieldV f -> FieldOf f
_ =: v = FieldOf v
fromField :: FieldOf f -> FieldV f
fromField (FieldOf v) = v
data Record :: [*] -> * where
RNil :: Record '[]
(:*:) :: Typeable f => FieldOf f -> Record t -> Record (f ': t)
data SameType a b where
Refl :: SameType a a
useProof :: SameType a b -> a -> b
useProof Refl a = a
newtype SF a b = SF (SameType (FieldOf a) (FieldOf b))
sf1 :: FieldOf f -> SF f f
sf1 _ = SF Refl
targetType :: f -> Maybe (SF g f)
targetType _ = Nothing
(?=) :: Typeable a => Record xs -> a -> Maybe (FieldV a)
RNil ?= _ = Nothing
(x :*: xs) ?= a = case (gcast (sf1 x)) `asTypeOf` (targetType a) of
Nothing -> xs ?= a
Just (SF y) -> Just . fromField $ useProof y x
x =? v = case x ?= v of
Just x -> x
Nothing -> error "this implementation under uses the type system"
data EmployeeName = EmployeeName deriving Typeable
type instance FieldV EmployeeName = String
data EmployeeID = EmployeeID deriving Typeable
type instance FieldV EmployeeID = Int
employee = (EmployeeName =: "James")
:*: ((EmployeeID =: 5) :*: RNil)
employeeName = employee =? EmployeeName
employeeId = employee =? EmployeeID这显然不如基于类型类的版本好。但是,如果您可以进行一些动态输入...
https://stackoverflow.com/questions/12124584
复制相似问题