2012-08-25 9 views
7

HaskellDB ile ilgili son mesajlar, tekrar HList içine bakmak için motive oldum. Halihazırda heterojen listelerin bir örneğine sahip olan GHC'de -XDataKinds'a sahip olduğumuz için, HList'lerin DataKind'ler ile nasıl göründüğünü araştırmak istedim. Bu beklenen bir durumdur ama bu projede amacım denemek ve mümkün olduğunca fazla tip sınıfları olmadan bunu yapmak için olduğu gibi çalışırBu DataKinds destekli heterojen liste uygulaması için OverlappingInstances öğesini kaldırmak mümkün mü?

{-# 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 

: Şu ana kadar takip var. Yani burada 2 soru var. İlk olarak, bir tip sınıfı olmadan (=?) (kayıt alanı erişim işlevi) yazmak mümkün mü? Değilse, çakışan örnekler olmadan yazılabilir mi?

İlk sorumun mümkün olmadığını hayal ediyorum ama belki ikinci olabilir. İnsanların ne düşündüğünü duymak isterim!

+0

Orijinal HList kağıdı, yalnızca "MultiParamTypeClasses" ve "FunctionalDependencies" kullanarak kurtulmayı başardığından, sadece DataKinds içine ekleyerek (ve kullanarak) düşünürdüm bunu değiştirmezdi. –

+0

@ Ptharien'sFlame the HList kağıdı TypeEq uygulamak için örtüşen kullanır kullanır. Diğer her şey TypeEq –

+0

@PhilipJF kullanılarak yapılabilir. Ardından tek ihtiyacınız olan 'TypeFamilies' ve' MultiParamTypeClasses', 'TypeEq' gerekli değil! –

cevap

2

Her iki sorunun cevabının da no olduğunu düşünüyorum. Sen sadece cant OverlappingInstances verir aslında ne formda

type family TypeEq a b :: Bool 
type instance TypeEq a a = True 
type instance TypeEq a b = False 

türüdür fonksiyonu var. Oleg, Type Level TypeReps kullanarak alternatif bir mekanizma önerdi, ancak henüz elimizde değil. Bu açıkça typeclass tabanlı sürüm olarak iyi değil tipi belirsiz

{-# 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 

kullanmak gibi çirkin "çözümler" var çünkü bu cevap, niteliklidir. Ancak, biraz dinamik yazım ile tamam iseniz ...

+0

Teşekkürler, bunu cevap olarak alacağım! Tüm seçenekler arasından en çok neyi beğendiğimi bilmiyorum. Ya hiçbir veri türü almıyoruz, örtüşen örneklerimiz var ya da ... – ocharles

İlgili konular