2012-08-25 4 views
7

हास्केल डीबी के बारे में हालिया पोस्ट के साथ, मुझे फिर से एचएलिस्ट को देखने के लिए प्रेरित किया गया है। चूंकि अब हमारे पास जीएचसी में -XDataKinds है, जिसमें वास्तव में विषम सूचियों का एक उदाहरण है, मैं जांच करना चाहता हूं कि एचएलिस्ट्स डेटाकिंड्स के साथ कैसे दिखते हैं।क्या इस डेटाकिंड्स-समर्थित विषम सूची कार्यान्वयन के लिए ओवरलैपिंग इंस्टेंस को निकालना संभव है?

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

यह उम्मीद है, लेकिन इस परियोजना में मेरा लक्ष्य कोशिश करते हैं और जितना संभव हो उतना प्रकार कक्षाओं के बिना यह करने के लिए था के रूप में काम करता है: अब तक, मैं निम्नलिखित है। तो यहां 2 प्रश्न हैं। सबसे पहले, क्या टाइप प्रकार के बिना (=?) (रिकॉर्ड फ़ील्ड एक्सेसर फ़ंक्शन) लिखना संभव है? यदि नहीं, तो क्या इसे ओवरलैपिंग उदाहरणों के बिना लिखा जा सकता है?

मुझे कल्पना है कि मेरे पहले प्रश्न के लिए यह संभव नहीं है, लेकिन शायद दूसरा संभव हो सकता है। मुझे यह जानना अच्छा लगेगा कि लोग क्या सोचते हैं!

+0

चूंकि मूल एचएलआईस्ट पेपर केवल 'मल्टीपाराम टाइप क्लासेस' और 'फंक्शनल डायरेक्टेंसीज' का उपयोग करने में कामयाब रहा, इसलिए मुझे लगता है कि 'डेटाकिंड्स) में केवल (और उपयोग) 'वह नहीं बदलेगा। –

+0

@ Ptharien'sFlame एचएलआईस्ट पेपर टाइपएक लागू करने के लिए ओवरलैपिंग इंस्टेंस का उपयोग करता है। TypeEq –

+0

@ फिलिपजेएफ का उपयोग करके बाकी सब कुछ किया जा सकता है, फिर आपको केवल 'TypeFamilies' और 'MultiParamTypeClasses' की आवश्यकता है, कोई 'TypeEq' आवश्यक नहीं है! –

उत्तर

2

मुझे लगता है कि दोनों प्रश्नों का उत्तर एक योग्य कोई है। आपके पास फॉर्म

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

का एक प्रकार का फ़ंक्शन नहीं हो सकता है जो अनिवार्य रूप से ओवरलैपिंग इंस्टेंस आपको देता है। ओलेग ने टाइप लेवल टाइपरप्स का उपयोग करके एक वैकल्पिक तंत्र का सुझाव दिया है, लेकिन हमारे पास अभी तक यह नहीं है। यह जवाब है, योग्य है, क्योंकि आप बदसूरत "समाधान" 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 

का उपयोग कर यह स्पष्ट रूप से typeclass आधारित संस्करण के रूप में के रूप में अच्छा नहीं है की तरह नहीं है। लेकिन, यदि आप थोड़ा गतिशील टाइपिंग के साथ ठीक हैं ...

+0

धन्यवाद, मैं इसे एक उत्तर के रूप में ले जाऊंगा! सभी विकल्पों में से मुझे यकीन नहीं है कि मुझे सबसे अच्छा क्या पसंद है। हम या तो कोई डेटा प्रकार, ओवरलैपिंग उदाहरण नहीं प्राप्त करते हैं, या हमें टाइप करने योग्य ... – ocharles

संबंधित मुद्दे