samrushing / irken-compiler

Irken is a statically typed variant of Scheme. Or a lisp-like variant of ML.

Home Page:http://nightmare.com/rushing/irken.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No way to create a container of polymorphic-open records.

samrushing opened this issue · comments

There is currently no way to create a list (or other container) of records with a restricted/open row type. It appears that a 'subtyping' cast operator is needed. This sample illustrates the problem:

(include "lib/basis.scm")

(typealias ralias (rproduct (rlabel f0 (pre int) 'a)))

(define (cast r)
  (%%cexp ((ralias 'a) -> (ralias 'b)) "%0" r)
  )

(define (dump-poly pl)
  (for-range i (length pl)
    (let ((item (nth pl i)))
      (printf (int i) " = " (int item.f0) "\n")
      )))

(define poly-list
  (cons (cast {f1=1})
        (cons (cast {f0=2 xyz=2})
              (cons (cast {f0=3 abc="hi"})
                    (list:nil)))))

(dump-poly poly-list)

I intend to revisit this issue later.

This mechanism in the code seems to work. By using %%cexp and casting both sides of it it to the desired cast-type, it forces the inference to unify both sides with the cast-type yet keeps a "boundary" in the middle across which the unification doesn't pass.

However, I can't seem to formulate a cast-to macro which accepts the type as an argument. Even if I could, the compile error if the macro wasn't used properly would be pretty bad, so it justifies something better.

NOTE: In theory I think it should be possible to do this hetro-unification automatically. It requires encoding %rextend as (pre) and %raccess as (abs). Then during unify, when unifying rows (abs 'a U _ 'a) -> (abs 'a); (pre 'a U pre 'a) -> (pre 'a); (pre 'a U ...) -> (...); (abs 'a U ...) -> type-error

In english, if either row has an (abs a) field, the both rows must have an a field and the resulting type includes (abs a); if both rows have (pre a) then the resulting type has (pre a), if only one row has (pre a) then the resulting type has no a field; and if one row has an (abs a) field, and the other row is i missing an a field, it's a type error.

(include "lib/basis.scm")

(typealias generic_row {field=int ...})

;; runtime polymorphic existential list
(typealias generic_list (list {field=int ...}) )

;; instantiate a runtime polymorphic ( existential ) list
(define a_var : (list {field=int ...})
    (list:nil))

(defmacro cast (cast x) ->  (%%cexp ( 'generic_row -> 'generic_row ) "%0" x))

; i tried to send the type as a parameter to macro, but it doesn't work
; (defmacro cast-to (cast-to x to-type) ->  (%%cexp ( to-type  -> to-type ) "%0" x))

(set! a_var (list:cons (cast {field=1 extra=2} ) a_var))
(set! a_var (list:cons (cast {field=2 bar=3}   ) a_var))
(set! a_var (list:cons (cast {field=3 zed="fo"} ) a_var))

;; (set! a_var (list:cons (cast {error="error"} ) a_var))


;; ...there is only going to be one parametric instantiation
;; of this function, which is going to be called on any data
;; placed in the list

(define (with_list a_list)
    (match a_list with
       (list:nil) -> #u
       (list:cons data next) ->
         (begin
            (printf (int data.field) "\n")
      ;      (printf (int data.foofield) "\n") ;; error
            (with_list next))
   )
)

(with_list a_var)