I have just checked in the container type part of the new PIL runcore: http://svn.openfoundry.org/pugs/src/PIL.hs
In the Pugs directory, you can run a sample test with: *PIL> tests ==> %ENV =:= %ENV; True ==> %ENV =:= %foo; False ==> untie(%ENV); my %foo := %ENV; () ==> my %foo := %ENV; Following is a semi-formal treatment for containers, directly transliterated from the Haskell source. Containers come in two flavours: Non-tieable and Tieable. Both are typed, mutable references. There is no way in runtime to change the flavour. data Container s a = NCon (STRef s (NBox a)) | TCon (STRef s (TBox a)) A Non-tieable container is comprised of an Id and a storage of that type, which can only be Scalar, Array or Hash. Again, there is no way to cast a Scalar container into a Hash container at runtime. type NBox a = (BoxId, a) A Tieable container also contains an Id and a storage, but also adds a tie-table that intercepts various operations for its type. type TBox a = (BoxId, a, Tieable a) The type of tie-table must agree with the storage type. Such a table may be empty, as denoted by the nullary constructor "Untied". Each of the three storage types comes with its own tie-table layout. data Tieable a where Untied :: Tieable a TieScalar :: TiedScalar -> Tieable Scalar TieArray :: TiedArray -> Tieable Array TieHash :: TiedHash -> Tieable Hash Binding only happens between containers of the same type: bind :: Container s a -> Container s a -> ST s () Additionally, the compiler needs to compile ($x := @y) into ($x := [EMAIL PROTECTED]). To bind a container to another, we first check to see if they are of the same tieableness. If so, we simply overwrite the target one's Id, storage and tie-table (if any): bind (TCon x) (TCon y) = writeSTRef x =<< readSTRef y bind (NCon x) (NCon y) = writeSTRef x =<< readSTRef y To bind an non-tieable container to a tieable one, we implicitly remove any current ties on the target, although it can be retied later: -- %*ENV := %foo bind (TCon x) (NCon y) = do (id, val) <- readSTRef y writeSTRef x (id, val, Untied) To bind a tieable container to a tied one, we first check if it is actually tied. If yes, we throw a runtime exception. If not, we proceed as if both were non-tieable. -- %foo := %*ENV bind (NCon x) (TCon y) = do (id, val, tied) <- readSTRef y case tied of Untied -> writeSTRef x (id, val) _ -> fail "Cannot bind a tied container to a non-tieable one" We can compare two containers for Id equivalence. If the container types differ, this should never return True: (=:=) :: Container s a -> Container s b -> ST s Bool x =:= y = do x_id <- readId x y_id <- readId y return (x_id == y_id) Untie an non-tieable container is a no-op: untie (NCon x) = return () For a tieable container, we first invokes the "UNTIE" handler, then set its "tied" slot to Untied: untie (TCon x) = do (id, val, tied) <- readSTRef x case tied of Untied -> return () _ -> do tied `invokeTie` UNTIE writeSTRef x (id, val, Untied) Thanks, /Autrijus/
pgpZ4bQLJ5AWC.pgp
Description: PGP signature