Is it possible in Haskell to get anything close to the dependency-tracking environment we implemented in R?.
First, there's no way it's gonna happen with regular variable assignment -- names in Haskell take on entirely unique and unchangeable values (this is right, isn't it?). So we're going to have to track names ourselves; I think using the HList module is probably appropriate.
-- Main.hs --
1 {-# LANGUAGE EmptyDataDecls #-} 2 {-# LANGUAGE DeriveDataTypeable #-} 3 {-# LANGUAGE TemplateHaskell #-} 4 5 import Data.HList 6 import Data.HList.Label4 7 import Data.HList.TypeEqGeneric1 8 import Data.HList.TypeCastGeneric1 9 import Data.HList.MakeLabels 10 11 $(makeLabels ["a", "b", "c"])
Now we have some language-accessible labels we can use. And we can build an HList Record to represent the "environment":
-- Main.hs (cont) --
13 reality = 14 a .=. 5 .*. 15 b .=. (reality#a) + 1 .*. 16 emptyRecord
This gives us the record we want,
-- Main.hs (cont) --
18 main = do 19 print reality
Record{a=5,b=6}
But changing one field won't change any of the others:
-- Main.hs (cont) --
18 main = do 19 let reality' = hUpdateAtLabel a 6 reality 20 print reality'
Record{a=6,b=6}
There are many ways we could deal with that; one way is to make reality a function and have it take itself as an argument:
-- Main.hs (cont) --
13 pReality x = 14 a .=. 5 .*. 15 b .=. (x#a) + 1 .*. 16 emptyRecord 17 18 reality = inf pReality
-- Main.hs (cont) --
20 inf f = f (inf f)
-- Main.hs (cont) --
22 main = do 23 print reality 24 let reality' = inf pReality' where 25 pReality' x = hUpdateAtLabel a 6 $ pReality x 26 print reality'
Record{a=5,b=6} Record{a=6,b=7}
That's better. We could add some syntactic sugar:
-- Main.hs (cont) --
20 pretend label value base = 21 inf (\x -> 22 hUpdateAtLabel label value (base x) 23 )
-- Main.hs (cont) --
27 main = do 28 let reality' = pretend a 6 pReality 29 print reality'
Record{a=6,b=7}
In R we kept track of which objects actually needed to be changed. He we just have a function pointing at everything; I don't know enough about how Haskell works to know whether that's inefficient; I'm not going to worry about it for now.
Notice that we cannot do this:
-- Main.hs (cont) --
13 $(label "p") 14 15 pReality x = 16 a .=. 5 .*. 17 b .=. (x#a) + 1 .*. 18 p .=. (pretend a 6 pReality) .*. 19 emptyRecord
Main.hs:15:0: Occurs check: cannot construct the infinite type: l' = HCons (LVPair (Proxy A) t) (HCons (LVPair (Proxy B) v) (HCons (LVPair (Proxy P) (Record l')) HNil)) Expected type: l' Inferred type: HCons (LVPair (Proxy A) t) (HCons (LVPair (Proxy B) v) (HCons (LVPair (Proxy P) (Record l')) HNil)) When using functional dependencies to combine HUpdateAtHNat HZero e' (HCons e l) (HCons e' l), arising from the dependency `n e l -> l'' in the instance declaration at <no location info> HUpdateAtHNat HZero (LVPair (Proxy A) t) (HCons (LVPair (Proxy A) t_a19b) (HCons (LVPair (Proxy B) v) (HCons (LVPair (Proxy P) (Record l')) HNil))) l', arising from a use of `pretend' at Main.hs:18:11-30 When generalising the type(s) for `pReality' Main.hs:29:19: No instances for (HFind (Proxy A) ls n, HUpdateAtHNat n (LVPair (Proxy A) t) t1 l') arising from a use of `pretend' at Main.hs:29:19-38 Possible fix: add an instance declaration for (HFind (Proxy A) ls n, HUpdateAtHNat n (LVPair (Proxy A) t) t1 l') In the expression: pretend a 6 pReality In the definition of `reality'': reality' = pretend a 6 pReality In the expression: do { let reality' = pretend a 6 pReality; print reality' }
But we can do this:
-- Main.hs (cont) --
13 pReality x = 14 a .=. 5 .*. 15 b .=. (x#a) + 1 .*. 16 c .=. (pretend a 6 pReality)#b .*. 17 emptyRecord
-- Main.hs (cont) --
26 main = do 27 print $ inf pReality
Record{a=5,b=6,c=7}
This is of course massively awkward, for a few reasons:
- We don't have a convenient way to represent assignments as actions (this is easy to fix).
- Haskell doesn't have anything like R's with(). This is a whole problem in itself. GHC does support dynamic binding (sort of), but it won't take an HList the way with() will take a list.
But (2) is a whole other topic for whole other day.
No comments:
Post a Comment