plpgsql: schema namespaces. refactor IO.
[jackhill/mal.git] / plpgsql / types.sql
index 5264848..62a63cc 100644 (file)
@@ -1,8 +1,6 @@
 -- ---------------------------------------------------------
 -- persistent values
 
-CREATE EXTENSION hstore;
-
 -- list of types for type_id
 -- 0:  nil
 -- 1:  false
@@ -19,41 +17,45 @@ CREATE EXTENSION hstore;
 -- 12: malfunc
 -- 13: atom
 
-CREATE SEQUENCE value_id_seq START WITH 3; -- skip nil, false, true
-CREATE TABLE value (
-    value_id        integer NOT NULL DEFAULT nextval('value_id_seq'),
-    type_id         integer NOT NULL,
-    val_int         bigint,    -- set for integers
-    val_string      varchar,   -- set for strings, keywords, symbols,
-                               -- and native functions (function name)
-    val_seq         integer[], -- set for lists and vectors
-    val_hash        hstore,    -- set for hash-maps
-    ast_id          integer,   -- set for malfunc
-    params_id       integer,   -- set for malfunc
-    env_id          integer,   -- set for malfunc
-    macro           boolean,   -- set for malfunc
-    meta_id         integer    -- can be set for any collection
-);
-ALTER TABLE value ADD CONSTRAINT pk_value_id
+CREATE SCHEMA types
+
+    CREATE SEQUENCE value_id_seq START WITH 3 -- skip nil, false, true
+
+    CREATE TABLE value (
+        value_id        integer NOT NULL DEFAULT nextval('value_id_seq'),
+        type_id         integer NOT NULL,
+        val_int         bigint,    -- set for integers
+        val_string      varchar,   -- set for strings, keywords, symbols,
+                                -- and native functions (function name)
+        val_seq         integer[], -- set for lists and vectors
+        val_hash        hstore,    -- set for hash-maps
+        ast_id          integer,   -- set for malfunc
+        params_id       integer,   -- set for malfunc
+        env_id          integer,   -- set for malfunc
+        macro           boolean,   -- set for malfunc
+        meta_id         integer    -- can be set for any collection
+    );
+
+ALTER TABLE types.value ADD CONSTRAINT pk_value_id
     PRIMARY KEY (value_id);
 -- drop sequence when table dropped
-ALTER SEQUENCE value_id_seq OWNED BY value.value_id;
-ALTER TABLE value ADD CONSTRAINT fk_meta_id
-    FOREIGN KEY (meta_id) REFERENCES value(value_id);
-ALTER TABLE value ADD CONSTRAINT fk_params_id
-    FOREIGN KEY (params_id) REFERENCES value(value_id);
+ALTER SEQUENCE types.value_id_seq OWNED BY types.value.value_id;
+ALTER TABLE types.value ADD CONSTRAINT fk_meta_id
+    FOREIGN KEY (meta_id) REFERENCES types.value(value_id);
+ALTER TABLE types.value ADD CONSTRAINT fk_params_id
+    FOREIGN KEY (params_id) REFERENCES types.value(value_id);
 
-CREATE INDEX ON value (value_id, type_id);
+CREATE INDEX ON types.value (value_id, type_id);
 
-INSERT INTO value (value_id, type_id) VALUES (0, 0); -- nil
-INSERT INTO value (value_id, type_id) VALUES (1, 1); -- false
-INSERT INTO value (value_id, type_id) VALUES (2, 2); -- true
+INSERT INTO types.value (value_id, type_id) VALUES (0, 0); -- nil
+INSERT INTO types.value (value_id, type_id) VALUES (1, 1); -- false
+INSERT INTO types.value (value_id, type_id) VALUES (2, 2); -- true
 
 
 -- ---------------------------------------------------------
 -- general functions
 
-CREATE FUNCTION _wraptf(val boolean) RETURNS integer AS $$
+CREATE FUNCTION types._wraptf(val boolean) RETURNS integer AS $$
 BEGIN
     IF val THEN
         RETURN 2;
@@ -63,7 +65,7 @@ BEGIN
 END; $$ LANGUAGE plpgsql IMMUTABLE;
 
 -- pun both NULL and false to false
-CREATE FUNCTION _tf(val boolean) RETURNS boolean AS $$
+CREATE FUNCTION types._tf(val boolean) RETURNS boolean AS $$
 BEGIN
     IF val IS NULL OR val = false THEN
         RETURN false;
@@ -72,7 +74,7 @@ BEGIN
 END; $$ LANGUAGE plpgsql IMMUTABLE;
 
 -- pun both NULL and 0 to false
-CREATE FUNCTION _tf(val integer) RETURNS boolean AS $$
+CREATE FUNCTION types._tf(val integer) RETURNS boolean AS $$
 BEGIN
     IF val IS NULL OR val = 0 THEN
         RETURN false;
@@ -81,13 +83,13 @@ BEGIN
 END; $$ LANGUAGE plpgsql IMMUTABLE;
 
 -- return the type of the given value_id
-CREATE FUNCTION _type(obj integer) RETURNS integer AS $$
+CREATE FUNCTION types._type(obj integer) RETURNS integer AS $$
 BEGIN
-    RETURN (SELECT type_id FROM value WHERE value_id = obj);
+    RETURN (SELECT type_id FROM types.value WHERE value_id = obj);
 END; $$ LANGUAGE plpgsql;
 
 
-CREATE FUNCTION _equal_Q(a integer, b integer) RETURNS boolean AS $$
+CREATE FUNCTION types._equal_Q(a integer, b integer) RETURNS boolean AS $$
 DECLARE
     atype  integer;
     btype  integer;
@@ -102,41 +104,42 @@ DECLARE
     kv     RECORD;
     i      integer;
 BEGIN
-    atype := _type(a);
-    btype := _type(b);
-    IF NOT ((atype = btype) OR (_sequential_Q(a) AND _sequential_Q(b))) THEN
+    atype := types._type(a);
+    btype := types._type(b);
+    IF NOT ((atype = btype) OR
+            (types._sequential_Q(a) AND types._sequential_Q(b))) THEN
         RETURN false;
     END IF;
     CASE
     WHEN atype = 3 THEN -- integer
-        SELECT val_int FROM value INTO anum WHERE value_id = a;
-        SELECT val_int FROM value INTO bnum WHERE value_id = b;
+        SELECT val_int FROM types.value INTO anum WHERE value_id = a;
+        SELECT val_int FROM types.value INTO bnum WHERE value_id = b;
         RETURN anum = bnum;
     WHEN atype = 5 OR atype = 7 THEN -- string/symbol
-        RETURN _valueToString(a) = _valueToString(b);
+        RETURN types._valueToString(a) = types._valueToString(b);
     WHEN atype IN (8, 9) THEN -- list/vector
-        IF _count(a) <> _count(b) THEN
+        IF types._count(a) <> types._count(b) THEN
             RETURN false;
         END IF;
-        SELECT val_seq INTO aseq FROM value WHERE value_id = a;
-        SELECT val_seq INTO bseq FROM value WHERE value_id = b;
-        FOR i IN 1 .. _count(a)
+        SELECT val_seq INTO aseq FROM types.value WHERE value_id = a;
+        SELECT val_seq INTO bseq FROM types.value WHERE value_id = b;
+        FOR i IN 1 .. types._count(a)
         LOOP
-            IF NOT _equal_Q(aseq[i], bseq[i]) THEN
+            IF NOT types._equal_Q(aseq[i], bseq[i]) THEN
                 return false;
             END IF;
         END LOOP;
         RETURN true;
     WHEN atype = 10 THEN -- hash-map
-        SELECT val_hash INTO ahash FROM value WHERE value_id = a;
-        SELECT val_hash INTO bhash FROM value WHERE value_id = b;
+        SELECT val_hash INTO ahash FROM types.value WHERE value_id = a;
+        SELECT val_hash INTO bhash FROM types.value WHERE value_id = b;
         IF array_length(akeys(ahash), 1) <> array_length(akeys(bhash), 1) THEN
             RETURN false;
         END IF;
         FOR kv IN SELECT * FROM each(ahash) LOOP
             avid := CAST((ahash -> kv.key) AS integer);
             bvid := CAST((bhash -> kv.key) AS integer);
-            IF bvid IS NULL OR NOT _equal_Q(avid, bvid) THEN
+            IF bvid IS NULL OR NOT types._equal_Q(avid, bvid) THEN
                 return false;
             END IF;
         END LOOP;
@@ -150,15 +153,15 @@ END; $$ LANGUAGE plpgsql;
 -- _clone:
 -- take a value_id of a collection
 -- returns a new value_id of a cloned collection
-CREATE FUNCTION _clone(id integer) RETURNS integer AS $$
+CREATE FUNCTION types._clone(id integer) RETURNS integer AS $$
 DECLARE
     result       integer;
 BEGIN
-    INSERT INTO value (type_id,val_int,val_string,val_seq,val_hash,
+    INSERT INTO types.value (type_id,val_int,val_string,val_seq,val_hash,
                        ast_id,params_id,env_id,meta_id)
         (SELECT type_id,val_int,val_string,val_seq,val_hash,
                 ast_id,params_id,env_id,meta_id
-              FROM value
+              FROM types.value
               WHERE value_id = id)
         RETURNING value_id INTO result;
     RETURN result;
@@ -172,7 +175,7 @@ END; $$ LANGUAGE plpgsql;
 -- _nil_Q:
 -- takes a value_id
 -- returns the whether value_id is nil
-CREATE FUNCTION _nil_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._nil_Q(id integer) RETURNS boolean AS $$
 BEGIN
     RETURN id = 0;
 END; $$ LANGUAGE plpgsql IMMUTABLE;
@@ -180,7 +183,7 @@ END; $$ LANGUAGE plpgsql IMMUTABLE;
 -- _true_Q:
 -- takes a value_id
 -- returns the whether value_id is true
-CREATE FUNCTION _true_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._true_Q(id integer) RETURNS boolean AS $$
 BEGIN
     RETURN id = 2;
 END; $$ LANGUAGE plpgsql IMMUTABLE;
@@ -188,7 +191,7 @@ END; $$ LANGUAGE plpgsql IMMUTABLE;
 -- _false_Q:
 -- takes a value_id
 -- returns the whether value_id is false
-CREATE FUNCTION _false_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._false_Q(id integer) RETURNS boolean AS $$
 BEGIN
     RETURN id = 1;
 END; $$ LANGUAGE plpgsql IMMUTABLE;
@@ -196,10 +199,10 @@ END; $$ LANGUAGE plpgsql IMMUTABLE;
 -- _string_Q:
 -- takes a value_id
 -- returns the whether value_id is string type
-CREATE FUNCTION _string_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._string_Q(id integer) RETURNS boolean AS $$
 BEGIN
-    IF (SELECT 1 FROM value WHERE type_id = 5 AND value_id = id) THEN
-        RETURN NOT _keyword_Q(id);
+    IF (SELECT 1 FROM types.value WHERE type_id = 5 AND value_id = id) THEN
+        RETURN NOT types._keyword_Q(id);
     END IF;
     RETURN false;
 END; $$ LANGUAGE plpgsql;
@@ -208,25 +211,25 @@ END; $$ LANGUAGE plpgsql;
 -- _valueToString:
 -- takes a value_id for a string
 -- returns the varchar value of the string
-CREATE FUNCTION _valueToString(sid integer) RETURNS varchar AS $$
+CREATE FUNCTION types._valueToString(sid integer) RETURNS varchar AS $$
 BEGIN
-    RETURN (SELECT val_string FROM value WHERE value_id = sid);
+    RETURN (SELECT val_string FROM types.value WHERE value_id = sid);
 END; $$ LANGUAGE plpgsql;
 
 -- _stringish:
 -- takes a varchar string
 -- returns the value_id of a stringish type (string, symbol, keyword)
-CREATE FUNCTION _stringish(str varchar, type integer) RETURNS integer AS $$
+CREATE FUNCTION types._stringish(str varchar, type integer) RETURNS integer AS $$
 DECLARE
     result  integer;
 BEGIN
     -- TODO: share string data between string types
     -- lookup if it exists
-    SELECT value_id FROM value INTO result
+    SELECT value_id FROM types.value INTO result
         WHERE val_string = str AND type_id = type;
     IF result IS NULL THEN
         -- Create string entry
-        INSERT INTO value (type_id, val_string)
+        INSERT INTO types.value (type_id, val_string)
             VALUES (type, str)
             RETURNING value_id INTO result;
     END IF;
@@ -236,28 +239,28 @@ END; $$ LANGUAGE plpgsql;
 -- _stringv:
 -- takes a varchar string
 -- returns the value_id of a string (new or existing)
-CREATE FUNCTION _stringv(str varchar) RETURNS integer AS $$
+CREATE FUNCTION types._stringv(str varchar) RETURNS integer AS $$
 BEGIN
-    RETURN _stringish(str, 5);
+    RETURN types._stringish(str, 5);
 END; $$ LANGUAGE plpgsql;
 
 -- _keywordv:
 -- takes a varchar string
 -- returns the value_id of a keyword (new or existing)
-CREATE FUNCTION _keywordv(name varchar) RETURNS integer AS $$
+CREATE FUNCTION types._keywordv(name varchar) RETURNS integer AS $$
 BEGIN
-    RETURN _stringish(chr(CAST(x'7f' AS integer)) || name, 5);
+    RETURN types._stringish(chr(CAST(x'7f' AS integer)) || name, 5);
 END; $$ LANGUAGE plpgsql;
 
 -- _keyword_Q:
 -- takes a value_id
 -- returns the whether value_id is keyword type
-CREATE FUNCTION _keyword_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._keyword_Q(id integer) RETURNS boolean AS $$
 DECLARE
     str  varchar;
 BEGIN
-    IF (SELECT 1 FROM value WHERE type_id = 5 AND value_id = id) THEN
-        str := _valueToString(id);
+    IF (SELECT 1 FROM types.value WHERE type_id = 5 AND value_id = id) THEN
+        str := types._valueToString(id);
         IF char_length(str) > 0 AND
            chr(CAST(x'7f' AS integer)) = substring(str FROM 1 FOR 1) THEN
             RETURN true;
@@ -269,31 +272,32 @@ END; $$ LANGUAGE plpgsql;
 -- _symbolv:
 -- takes a varchar string
 -- returns the value_id of a symbol (new or existing)
-CREATE FUNCTION _symbolv(name varchar) RETURNS integer AS $$
+CREATE FUNCTION types._symbolv(name varchar) RETURNS integer AS $$
 BEGIN
-    RETURN _stringish(name, 7);
+    RETURN types._stringish(name, 7);
 END; $$ LANGUAGE plpgsql;
 
 -- _symbol_Q:
 -- takes a value_id
 -- returns the whether value_id is symbol type
-CREATE FUNCTION _symbol_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._symbol_Q(id integer) RETURNS boolean AS $$
 BEGIN
-    RETURN _tf((SELECT 1 FROM value WHERE type_id = 7 AND value_id = id));
+    RETURN types._tf((SELECT 1 FROM types.value
+            WHERE type_id = 7 AND value_id = id));
 END; $$ LANGUAGE plpgsql;
 
 -- _numToValue:
 -- takes an bigint number
 -- returns the value_id for the number
-CREATE FUNCTION _numToValue(num bigint) RETURNS integer AS $$
+CREATE FUNCTION types._numToValue(num bigint) RETURNS integer AS $$
 DECLARE
     result  integer;
 BEGIN
-    SELECT value_id FROM value INTO result
+    SELECT value_id FROM types.value INTO result
         WHERE val_int = num AND type_id = 3;
     IF result IS NULL THEN
         -- Create an integer entry
-        INSERT INTO value (type_id, val_int)
+        INSERT INTO types.value (type_id, val_int)
             VALUES (3, num)
             RETURNING value_id INTO result;
     END IF;
@@ -305,28 +309,28 @@ END; $$ LANGUAGE plpgsql;
 
 -- _sequential_Q:
 -- return true if obj value_id is a list or vector
-CREATE FUNCTION _sequential_Q(obj integer) RETURNS boolean AS $$
+CREATE FUNCTION types._sequential_Q(obj integer) RETURNS boolean AS $$
 BEGIN
-    RETURN _tf((SELECT 1 FROM value
+    RETURN types._tf((SELECT 1 FROM types.value
                 WHERE value_id = obj AND (type_id = 8 OR type_id = 9)));
 END; $$ LANGUAGE plpgsql;
 
 -- _collection:
 -- takes a array of value_id integers
 -- returns the value_id of a new list (8), vector (9) or hash-map (10)
-CREATE FUNCTION _collection(items integer[], type integer) RETURNS integer AS $$
+CREATE FUNCTION types._collection(items integer[], type integer) RETURNS integer AS $$
 DECLARE
     vid  integer;
 BEGIN
     IF type IN (8, 9) THEN
-        INSERT INTO value (type_id, val_seq)
+        INSERT INTO types.value (type_id, val_seq)
             VALUES (type, items)
             RETURNING value_id INTO vid;
     ELSIF type = 10 THEN
         IF (array_length(items, 1) % 2) = 1 THEN
             RAISE EXCEPTION 'hash-map: odd number of arguments';
         END IF;
-        INSERT INTO value (type_id, val_hash)
+        INSERT INTO types.value (type_id, val_hash)
             VALUES (type, hstore(CAST(items AS varchar[])))
             RETURNING value_id INTO vid;
     END IF;
@@ -337,42 +341,44 @@ END; $$ LANGUAGE plpgsql;
 -- _list:
 -- takes a array of value_id integers
 -- returns the value_id of a new list
-CREATE FUNCTION _list(items integer[]) RETURNS integer AS $$
+CREATE FUNCTION types._list(items integer[]) RETURNS integer AS $$
 BEGIN
-    RETURN _collection(items, 8);
+    RETURN types._collection(items, 8);
 END; $$ LANGUAGE plpgsql;
 
 -- _vector:
 -- takes a array of value_id integers
 -- returns the value_id of a new list
-CREATE FUNCTION _vector(items integer[]) RETURNS integer AS $$
+CREATE FUNCTION types._vector(items integer[]) RETURNS integer AS $$
 BEGIN
-    RETURN _collection(items, 9);
+    RETURN types._collection(items, 9);
 END; $$ LANGUAGE plpgsql;
 
 -- _list_Q:
 -- return true if obj value_id is a list
-CREATE FUNCTION _list_Q(obj integer) RETURNS boolean AS $$
+CREATE FUNCTION types._list_Q(obj integer) RETURNS boolean AS $$
 BEGIN
-    RETURN _tf((SELECT 1 FROM value WHERE value_id = obj and type_id = 8));
+    RETURN types._tf((SELECT 1 FROM types.value
+            WHERE value_id = obj and type_id = 8));
 END; $$ LANGUAGE plpgsql;
 
 -- _vector_Q:
 -- return true if obj value_id is a list
-CREATE FUNCTION _vector_Q(obj integer) RETURNS boolean AS $$
+CREATE FUNCTION types._vector_Q(obj integer) RETURNS boolean AS $$
 BEGIN
-    RETURN _tf((SELECT 1 FROM value WHERE value_id = obj and type_id = 9));
+    RETURN types._tf((SELECT 1 FROM types.value
+            WHERE value_id = obj and type_id = 9));
 END; $$ LANGUAGE plpgsql;
 
 
 -- _valueToArray:
 -- takes an value_id referring to a list or vector
 -- returns an array of the value_ids from the list/vector
-CREATE FUNCTION _valueToArray(seq integer) RETURNS integer[] AS $$
+CREATE FUNCTION types._valueToArray(seq integer) RETURNS integer[] AS $$
 DECLARE
     result  integer[];
 BEGIN
-    result := (SELECT val_seq FROM value WHERE value_id = seq);
+    result := (SELECT val_seq FROM types.value WHERE value_id = seq);
     IF result IS NULL THEN
         result := ARRAY[]::integer[];
     END IF;
@@ -380,7 +386,7 @@ BEGIN
 END; $$ LANGUAGE plpgsql;
 
 -- From: https://wiki.postgresql.org/wiki/Array_reverse
-CREATE FUNCTION array_reverse(a integer[]) RETURNS integer[] AS $$
+CREATE FUNCTION types.array_reverse(a integer[]) RETURNS integer[] AS $$
 SELECT ARRAY(
     SELECT a[i]
     FROM generate_subscripts(a,1) AS s(i)
@@ -392,37 +398,37 @@ $$ LANGUAGE 'sql' STRICT IMMUTABLE;
 -- _nth:
 -- takes value_id and an index
 -- returns the value_id of nth element in list/vector
-CREATE FUNCTION _nth(seq_id integer, indx integer) RETURNS integer AS $$
+CREATE FUNCTION types._nth(seq_id integer, indx integer) RETURNS integer AS $$
 DECLARE
     result  integer;
 BEGIN
-    RETURN (SELECT val_seq[indx+1] FROM value WHERE value_id = seq_id);
+    RETURN (SELECT val_seq[indx+1] FROM types.value WHERE value_id = seq_id);
 END; $$ LANGUAGE plpgsql;
 
 -- _first:
 -- takes value_id
 -- returns the value_id of first element in list/vector
-CREATE FUNCTION _first(seq_id integer) RETURNS integer AS $$
+CREATE FUNCTION types._first(seq_id integer) RETURNS integer AS $$
 BEGIN
-    RETURN _nth(seq_id, 0);
+    RETURN types._nth(seq_id, 0);
 END; $$ LANGUAGE plpgsql;
 
 
 -- _restArray:
 -- takes value_id
 -- returns the array of value_ids
-CREATE FUNCTION _restArray(seq_id integer) RETURNS integer[] AS $$
+CREATE FUNCTION types._restArray(seq_id integer) RETURNS integer[] AS $$
 DECLARE
     result  integer[];
 BEGIN
-    result := (SELECT val_seq FROM value WHERE value_id = seq_id);
+    result := (SELECT val_seq FROM types.value WHERE value_id = seq_id);
     RETURN result[2:array_length(result, 1)];
 END; $$ LANGUAGE plpgsql;
 
 -- _slice:
 -- takes value_id, a first index and an last index
 -- returns the value_id of new list from first (inclusive) to last (exclusive)
-CREATE FUNCTION _slice(seq_id integer, first integer, last integer)
+CREATE FUNCTION types._slice(seq_id integer, first integer, last integer)
 RETURNS integer AS $$
 DECLARE
     seq            integer[];
@@ -430,8 +436,8 @@ DECLARE
     i              integer;
     result         integer;
 BEGIN
-    SELECT val_seq INTO seq FROM value WHERE value_id = seq_id;
-    INSERT INTO value (type_id, val_seq)
+    SELECT val_seq INTO seq FROM types.value WHERE value_id = seq_id;
+    INSERT INTO types.value (type_id, val_seq)
         VALUES (8, seq[first+1:last])
         RETURNING value_id INTO result;
     RETURN result;
@@ -440,19 +446,19 @@ END; $$ LANGUAGE plpgsql;
 -- _rest:
 -- takes value_id
 -- returns the value_id of new list
-CREATE FUNCTION _rest(seq_id integer) RETURNS integer AS $$
+CREATE FUNCTION types._rest(seq_id integer) RETURNS integer AS $$
 BEGIN
-    RETURN _slice(seq_id, 1, _count(seq_id));
+    RETURN types._slice(seq_id, 1, types._count(seq_id));
 END; $$ LANGUAGE plpgsql;
 
 -- _count:
 -- takes value_id
 -- returns a count (not value_id)
-CREATE FUNCTION _count(seq_id integer) RETURNS integer AS $$
+CREATE FUNCTION types._count(seq_id integer) RETURNS integer AS $$
 DECLARE
     result  integer[];
 BEGIN
-    result := (SELECT val_seq FROM value
+    result := (SELECT val_seq FROM types.value
                          WHERE value_id = seq_id);
     RETURN COALESCE(array_length(result, 1), 0);
 END; $$ LANGUAGE plpgsql;
@@ -463,33 +469,35 @@ END; $$ LANGUAGE plpgsql;
 
 -- _hash_map:
 -- return value_id of a new hash-map
-CREATE FUNCTION _hash_map(items integer[]) RETURNS integer AS $$
+CREATE FUNCTION types._hash_map(items integer[]) RETURNS integer AS $$
 BEGIN
-    RETURN _collection(items, 10);
+    RETURN types._collection(items, 10);
 END; $$ LANGUAGE plpgsql;
 
 -- _hash_map_Q:
 -- return true if obj value_id is a list
-CREATE FUNCTION _hash_map_Q(obj integer) RETURNS boolean AS $$
+CREATE FUNCTION types._hash_map_Q(obj integer) RETURNS boolean AS $$
 BEGIN
-    RETURN _tf((SELECT 1 FROM value WHERE value_id = obj and type_id = 10));
+    RETURN types._tf((SELECT 1 FROM types.value
+            WHERE value_id = obj and type_id = 10));
 END; $$ LANGUAGE plpgsql;
 
 -- _assoc_BANG:
 -- return value_id of the hash-map with new elements appended
-CREATE FUNCTION _assoc_BANG(hm integer, items integer[]) RETURNS integer AS $$
+CREATE FUNCTION types._assoc_BANG(hm integer, items integer[]) RETURNS integer AS $$
 DECLARE
     hash  hstore;
 BEGIN
     IF (array_length(items, 1) % 2) = 1 THEN
         RAISE EXCEPTION 'hash-map: odd number of arguments';
     END IF;
-    SELECT val_hash INTO hash FROM value WHERE value_id = hm;
+    SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
     IF hash IS NULL THEN
-        UPDATE value SET val_hash = hstore(CAST(items AS varchar[]))
+        UPDATE types.value SET val_hash = hstore(CAST(items AS varchar[]))
             WHERE value_id = hm;
     ELSE
-        UPDATE value SET val_hash = hash || hstore(CAST(items AS varchar[]))
+        UPDATE types.value
+            SET val_hash = hash || hstore(CAST(items AS varchar[]))
             WHERE value_id = hm;
     END IF;
     RETURN hm;
@@ -497,53 +505,53 @@ END; $$ LANGUAGE plpgsql;
 
 -- _dissoc_BANG:
 -- return value_id of the hash-map with elements removed
-CREATE FUNCTION _dissoc_BANG(hm integer, items integer[]) RETURNS integer AS $$
+CREATE FUNCTION types._dissoc_BANG(hm integer, items integer[]) RETURNS integer AS $$
 DECLARE
     hash  hstore;
 BEGIN
-    SELECT val_hash INTO hash FROM value WHERE value_id = hm;
-    UPDATE value SET val_hash = hash - CAST(items AS varchar[])
+    SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
+    UPDATE types.value SET val_hash = hash - CAST(items AS varchar[])
             WHERE value_id = hm;
     RETURN hm;
 END; $$ LANGUAGE plpgsql;
 
 -- _get:
 -- return value_id of the hash-map entry matching key
-CREATE FUNCTION _get(hm integer, key varchar) RETURNS integer AS $$
+CREATE FUNCTION types._get(hm integer, key varchar) RETURNS integer AS $$
 DECLARE
     hash  hstore;
 BEGIN
-    SELECT val_hash INTO hash FROM value WHERE value_id = hm;
-    RETURN hash -> CAST(_stringv(key) AS varchar);
+    SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
+    RETURN hash -> CAST(types._stringv(key) AS varchar);
 END; $$ LANGUAGE plpgsql;
 
 -- _contains_Q:
 -- return true if hash-map contains entry matching key
-CREATE FUNCTION _contains_Q(hm integer, key varchar) RETURNS boolean AS $$
+CREATE FUNCTION types._contains_Q(hm integer, key varchar) RETURNS boolean AS $$
 DECLARE
     hash  hstore;
 BEGIN
-    SELECT val_hash INTO hash FROM value WHERE value_id = hm;
-    RETURN _tf(hash ? CAST(_stringv(key) AS varchar));
+    SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
+    RETURN types._tf(hash ? CAST(types._stringv(key) AS varchar));
 END; $$ LANGUAGE plpgsql;
 
 -- _keys:
 -- return array of key value_ids from hash-map
-CREATE FUNCTION _keys(hm integer) RETURNS integer[] AS $$
+CREATE FUNCTION types._keys(hm integer) RETURNS integer[] AS $$
 DECLARE
     hash  hstore;
 BEGIN
-    SELECT val_hash INTO hash FROM value WHERE value_id = hm;
+    SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
     RETURN CAST(akeys(hash) AS integer[]);
 END; $$ LANGUAGE plpgsql;
 
 -- _vals:
 -- return array of value value_ids from hash-map
-CREATE FUNCTION _vals(hm integer) RETURNS integer[] AS $$
+CREATE FUNCTION types._vals(hm integer) RETURNS integer[] AS $$
 DECLARE
     hash  hstore;
 BEGIN
-    SELECT val_hash INTO hash FROM value WHERE value_id = hm;
+    SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
     RETURN CAST(avals(hash) AS integer[]);
 END; $$ LANGUAGE plpgsql;
 
@@ -554,12 +562,12 @@ END; $$ LANGUAGE plpgsql;
 -- _function:
 -- takes a function name
 -- returns the value_id of a new 
-CREATE FUNCTION _function(fname varchar)
+CREATE FUNCTION types._function(fname varchar)
 RETURNS varchar AS $$
 DECLARE
     result  integer;
 BEGIN
-    INSERT INTO value (type_id, val_string)
+    INSERT INTO types.value (type_id, val_string)
         VALUES (11, fname)
         RETURNING value_id INTO result;
     RETURN CAST(result AS varchar);
@@ -568,31 +576,31 @@ END; $$ LANGUAGE plpgsql;
 -- _malfunc:
 -- takes a ast value_id, params value_id and env_id
 -- returns the value_id of a new function
-CREATE FUNCTION _malfunc(ast integer, params integer, env integer)
+CREATE FUNCTION types._malfunc(ast integer, params integer, env integer)
 RETURNS integer AS $$
 DECLARE
     cid     integer = NULL;
     result  integer;
 BEGIN
     -- Create function entry
-    INSERT INTO value (type_id, ast_id, params_id, env_id)
+    INSERT INTO types.value (type_id, ast_id, params_id, env_id)
         VALUES (12, ast, params, env)
         RETURNING value_id into result;
     RETURN result;
 END; $$ LANGUAGE plpgsql;
 
 -- _macro:
-CREATE FUNCTION _macro(func integer) RETURNS integer AS $$
+CREATE FUNCTION types._macro(func integer) RETURNS integer AS $$
 DECLARE
     newfunc  integer;
     cid      integer;
 BEGIN
-    newfunc := _clone(func);
-    UPDATE value SET macro = true WHERE value_id = newfunc;
+    newfunc := types._clone(func);
+    UPDATE types.value SET macro = true WHERE value_id = newfunc;
     RETURN newfunc;
 END; $$ LANGUAGE plpgsql;
 
-CREATE FUNCTION _apply(func integer, args integer[]) RETURNS integer AS $$
+CREATE FUNCTION types._apply(func integer, args integer[]) RETURNS integer AS $$
 DECLARE
     type     integer;
     fcid     integer;
@@ -604,14 +612,14 @@ DECLARE
 BEGIN
     SELECT type_id, val_string, ast_id, params_id, env_id
         INTO type, fname, fast, fparams, fenv
-        FROM value WHERE value_id = func;
+        FROM types.value WHERE value_id = func;
     IF type = 11 THEN
         EXECUTE format('SELECT %s($1);', fname)
             INTO result USING args;
         RETURN result;
     ELSIF type = 12 THEN
         -- NOTE: forward reference to current step EVAL function
-        RETURN EVAL(fast, env_new_bindings(fenv, fparams, args));
+        RETURN mal.EVAL(fast, envs.new(fenv, fparams, args));
     ELSE
         RAISE EXCEPTION 'Invalid function call';
     END IF;
@@ -623,13 +631,13 @@ END; $$ LANGUAGE plpgsql;
 -- _atom:
 -- takes an ast value_id
 -- returns a new atom value_id
-CREATE FUNCTION _atom(val integer) RETURNS integer AS $$
+CREATE FUNCTION types._atom(val integer) RETURNS integer AS $$
 DECLARE
     cid     integer = NULL;
     result  integer;
 BEGIN
     -- Create atom
-    INSERT INTO value (type_id, val_seq)
+    INSERT INTO types.value (type_id, val_seq)
         VALUES (13, ARRAY[val])
         RETURNING value_id INTO result;
     RETURN result;
@@ -638,26 +646,27 @@ END; $$ LANGUAGE plpgsql;
 -- _atom_Q:
 -- takes a value_id
 -- returns the whether value_id is an atom
-CREATE FUNCTION _atom_Q(id integer) RETURNS boolean AS $$
+CREATE FUNCTION types._atom_Q(id integer) RETURNS boolean AS $$
 BEGIN
-    RETURN EXISTS(SELECT 1 FROM value WHERE type_id = 13 AND value_id = id);
+    RETURN EXISTS(SELECT 1 FROM types.value
+        WHERE type_id = 13 AND value_id = id);
 END; $$ LANGUAGE plpgsql;
 
 -- _deref:
 -- takes an atom value_id
 -- returns a atom value value_id
-CREATE FUNCTION _deref(atm integer) RETURNS integer AS $$
+CREATE FUNCTION types._deref(atm integer) RETURNS integer AS $$
 DECLARE
     result  integer;
 BEGIN
-    RETURN (SELECT val_seq[1] FROM value WHERE value_id = atm);
+    RETURN (SELECT val_seq[1] FROM types.value WHERE value_id = atm);
 END; $$ LANGUAGE plpgsql;
 
 -- _reset_BANG:
 -- takes an atom value_id and new value value_id
 -- returns a new value value_id
-CREATE FUNCTION _reset_BANG(atm integer, newval integer) RETURNS integer AS $$
+CREATE FUNCTION types._reset_BANG(atm integer, newval integer) RETURNS integer AS $$
 BEGIN
-    UPDATE value SET val_seq = ARRAY[newval] WHERE value_id = atm;
+    UPDATE types.value SET val_seq = ARRAY[newval] WHERE value_id = atm;
     RETURN newval;
 END; $$ LANGUAGE plpgsql;