XtLang questions

67 views
Skip to first unread message

Cian O'Connor

unread,
Oct 19, 2017, 8:08:01 AM10/19/17
to Extempore
I'm currently working on updating the documentation for XtLang. Inevitably as I work through the docs and Andrew's examples I have questions. If anyone could answer these it would be great:
  1. Does XtLang have unsigned types? (e.g. Unsigned intetegers). If not, what is the protocol for interface with C libraries that expect these?
  2. Enumerations. Does XTLang support these? I've seen the alias enum which is a way of creating a C style alias for enumerations, but I haven't seen any way to create a typed enumerated data type.

Algebraic Data Types

Question 1
In Haskell you can do the following with Algebraic Data Types:
data Thing = Shoe
           | Ship
           | SealingWax
           | Cabbage
           | King

(Which is obviously a type of enumeration). I haven't been able to find a way to do this with ADTs in XtLang. When I try something like this:
(bind-data Thing
    (Shoe)
    (Ship)
    (SealingWax)
  )

I get the following (slightly cryptic) error message:
DataType:  Thing >>> <i64,i8*>
function(cdr): argument 1 must be: pair
argument values: ("%Thing") #<PROC cdr>
Trace: cdddr <- bind-data-type-constructor <- impc:ti:run <- impc:ti:compile-type-dataconstructors


Question 2
Is there a way to have non generic definitions for ADTs

Let's say I want to do the following
(bind-data Either{!a,!b}
             (Left !a)
             (Right !b))

but instead of using generics, I want to use concrete types. How would I do that?






Andrew Sorensen

unread,
Oct 19, 2017, 8:25:55 PM10/19/17
to extemp...@googlegroups.com
Hey Cian,

XTLang doesn't have a very good 'unsigned' story at the moment.  The simple answer is that we expect everything to be signed and conversion from unsigned is an exercise left to the reader.  

The slightly more complicated answer is that for many internal operations we don't actually care if the data is signed or unsigned, this is true for multiplication, addition and subtraction.  We also support a number of conversion routines with support for unsigned variants: ui64tod for example converts unsigned i64 to double and dtoui64 to go back.  Nonetheless, unsigned is a second class citizen at best, and we should do better :)

ADTs:  First thing, you found a bug, thanks :)  It's now fixed in HEAD.  ADTs in XTLang are brand spanking new and are guaranteed to have some teething problems.  To my knowledge you are only the second person to actually try to use them :)

I think the examples below (and the bug fix) will answer all your question.  Note that you'll need to latest from git for this to work.

Worth noting ahead of time is the *very* long compile time of "test_the_generic_stuff" - don't give up on it, it will get there :). Fixing this excessive compilation time is *the* major agenda item for v1.0, and is also why I haven't really started 'promoting' ADTs.  Once the compilation performance issues are fixed, all the core libraries will be rewritten and ADTs will obviously be a big part of that.

--------------------------------

;; load in ADT support
(sys:load "libs/base/adt.xtm")

;;
;; an ADT List for our use in this example
;;
(bind-data List{!a}
           (Nil)
           (Cons !a List{!a}*))

(bind-func map:[List{!b}*,[!b,!a]*,List{!a}*]*
  (lambda (f F)
    (Cons$ F (x xs)
           (Cons (f x) (map f xs))  ;; F did match Cons
           (Nil))))                 ;; F did not match Cons

(bind-func print:[void,List{!a}*]*
  (lambda (lst)
    (map (lambda (x) (printout x " ") x) lst)
    void))

;; list macro
(define (_List ast)
  (if (null? ast)
      `(Nil)
      `(Cons ,(car ast) ,(_List (cdr ast)))))

;; xtlang macro
(bind-macro (List . ast) (_List ast))



;;
;; enumerate the THINGS
;;
(bind-data Thing (Shoe) (Ship) (King))

;; overload print for Thing
(bind-func print
  (lambda (x:Thing*)
    (Shoe$ x () (printout "Shoe") void)  ;; printout returns void 
    (Ship$ x () (printout "Ship") void)  ;; so fail case
    (King$ x () (printout "King") void)  ;; must also return void
    void))

(bind-func test_the_things
  (lambda ()
    (let ((shoe (Shoe))
          (ship (Ship))
          (king (King)))
      (List shoe ship king))))

($ (println (test_the_things)))

;; or more directly
($ (println (List (King) (Ship) (Shoe))))


;;
;; Constainers of (non generic) Stuff
;;
(bind-data Container
           (CShoe float)
           (CShip i32)
           (CKing i64 double))

;; overload print for Thing
(bind-func print
  (lambda (c:Container*)
    (CShoe$ c (x) (printout "<Shoe:" x ">") void)
    (CShip$ c (x) (printout "<Ship:" x ">") void)
    (CKing$ c (x y) (printout "<King:" x "," y ">") void)
    void))

(bind-func test_the_typed_stuff
  (lambda ()
    (let ((shoe (CShoe 1.0))
          (ship (CShip 2))
          (king (CKing 3 4.0)))
      (List shoe ship king))))

($ (println (test_the_typed_stuff)))

;;
;; Constainers of generic Stuff
;;
(bind-data GContainer{!a,!b}
           (GCShoe !a)
           (GCShip !b)
           (GCKing !a !b))

;; overload print for Thing
(bind-func print:[void,GContainer{!a,!b}*]*
  (lambda (c)
    (GCShoe$ c (x) (printout "<Shoe:" x ">") void)
    (GCShip$ c (x) (printout "<Ship:" x ">") void)
    (GCKing$ c (x y) (printout "<King:" x "," y ">") void)
    void))

;; this might take some time to compile :(
(bind-func test_the_generic_stuff
  (lambda ()
    (let ((shoe (GCShoe 1))
          (ship (GCShip 2.0))
          (king (GCKing 3 4.0))
          (shoe2 (GCShoe 'A'))  ;; literal string
          (ship2 (GCShip 'B))   ;; literal symbol
          (king2 (GCKing 'C' 'D)))
      (println 'List_1 (List shoe ship king))
      (println 'List_2 (List king2 ship2 shoe2))
      void)))

($ (test_the_generic_stuff))








--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelang+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Toby Gifford

unread,
Oct 19, 2017, 9:59:02 PM10/19/17
to extemp...@googlegroups.com
Nice, so "bind-data" is a new generic thingy?

Andrew Sorensen

unread,
Oct 20, 2017, 12:40:23 AM10/20/17
to extemp...@googlegroups.com
Hey Tobes,
 
A new datatype, that can be generic or concrete.  

;; define concrete binary tree
(bind-data Tree (Empty) (Leaf double) (Node Tree* Tree*))

;; define generic binary tree
(bind-data Tree{!a} (Empty) (Leaf !a) (Node Tree{!a}* Tree{!a}*))

Cheers,
Andrew.

Toby Gifford

unread,
Oct 20, 2017, 12:46:04 AM10/20/17
to extemp...@googlegroups.com
Having just done a quick read up on Algebraic Data Types, I have a question - are these more like product or sum types?
I've been writing a Variant data type library, maybe I could use an ADT instead? The use case i'm aiming for is an XTlang based general OSC receiving function.

Andrew Sorensen

unread,
Oct 20, 2017, 1:09:14 AM10/20/17
to extemp...@googlegroups.com
XTLang Tuples are 'product types'
XTLang ADTs are 'sum types'


Andrew Sorensen

unread,
Oct 20, 2017, 1:11:20 AM10/20/17
to extemp...@googlegroups.com
Can you give us a high level example of what you're trying to do?

Toby Gifford

unread,
Oct 20, 2017, 1:15:42 AM10/20/17
to extemp...@googlegroups.com

(bind-func osc_send:[void,i8*,i64,i8*,List{Variant*}*]*
  (lambda (host port address args)
    (let* ((h:OSCHost* (OSCHost (String host) port))
           (a:OSCAddress* (String address))
           (t:OSCTypeString* (osc_typestring args))
           (m:OSCMessage* (OSCMessage a t args)))
      (send h m))))


($ (osc_send "localhost" 7019 "/snibble/X" (list (Variant 33:i32) (Variant 22.2:float) (Variant (String "snobble")))))
    

Andrew Sorensen

unread,
Oct 20, 2017, 2:47:57 AM10/20/17
to extemp...@googlegroups.com
Ok, so I got a little carried away :)

This is a partial, and almost completely untested example, without any error handling, but should get you off to a good start.

Note that you *should not* load libs/core/adt.xtm.  The example is self contained. 

Cheers,
Andrew.


;; load in ADT support
(sys:load "libs/base/adt.xtm")

;;
;; an ADT List for our use in this example
;;
(bind-data List{!a}
           (Nil)
           (Cons !a List{!a}*))

(bind-func map:[List{!b}*,[!b,!a]*,List{!a}*]*
  (lambda (f F)
    (Cons$ F (x xs)
           (Cons (f x) (map f xs))  ;; F did match Cons
           (Nil))))                 ;; F did not match Cons

(bind-func foldl:[!b,[!b,!b,!a]*,!b,List{!a}*]*
  (lambda (fn start lst)
    (Cons$ lst (x xs)
           (foldl fn (fn start x) xs)
           start)))

(bind-func print:[void,List{!a}*]*
  (lambda (lst)
    (map (lambda (x) (printout x " ") x) lst)
    void))

;; list macro
(define (_List ast)
  (if (null? ast)
      `(Nil)
      `(Cons ,(car ast) ,(_List (cdr ast)))))

;; xtlang macro
(bind-macro (List . ast) (_List ast))




(bind-data OscValue
           (OscInt i32)
           (OscFloat float)           
           (OscString String*))

;; return type string
(bind-func get_osc_type_string
  (lambda (obj:OscValue*)
    (OscInt$ obj (x) 'i'
      (OscFloat$ obj (x) 'f'
        (OscString$ obj (x) 's'
          (String "Bad Type!"))))))

(bind-func get_osc_str_lgth
  (lambda (s:String*)
    (let ((mod (% (+ (length s) 1) 4)))
      (+ (+ (length s) 1)
         (if (= 0 mod) 0 (- 4 mod))))))

(bind-func get_osc_type_size
  (lambda (obj:OscValue*)
    (OscInt$ obj (x) 4
       (OscFloat$ obj (x) 4 
                  (OscString$ obj (x) (get_osc_str_lgth x) 0)))))

(bind-func calc_osc_type_string
  (lambda (values:List{OscValue*}*)
    (foldl (lambda (osctype:String* oscvalue:OscValue*)
              (cat osctype (get_osc_type_string oscvalue)))
            (String ",")
            values)))

(bind-func calc_osc_args_size
  (lambda (values:List{OscValue*}*)
    (foldl (lambda (size:i64 oscvalue:OscValue*)
              (+ size (get_osc_type_size oscvalue)))
           0 values)))

(bind-func add_osc_value_to_payload
  (lambda (obj:OscValue* data:i8*)
    (OscInt$ obj (x) (pset! (cast data i32*) 0 (swap32i x)) 0:i32)
    (OscFloat$ obj (x) (pset! (cast data i32*) 0 (swap32f x)) 0:i32)    
    (OscString$ obj (x) (memcpy data (cstring x) (length x)) void)
    (pref-ptr data (get_osc_type_size obj))))

(bind-func send_osc_msg
  (lambda (host:String* port:i32 address:String* args:List{OscValue*}*)
    (let ((typestr (calc_osc_type_string args))
          (size_of_typestr (get_osc_str_lgth typestr))
          (size_of_address (get_osc_str_lgth address))
          (size_of_args (calc_osc_args_size args))
          (msgsize (+ size_of_typestr size_of_address size_of_args))
          (data:i8* (alloc msgsize))
          (values (Cons (OscString address) (Cons (OscString typestr) args))))
      (println 'address: address 'address_size: size_of_address)
      (println 'typestr: typestr 'typestr_size: size_of_typestr)
      (println 'size_of_args: size_of_args 'msg_size: msgsize)
      (foldl (lambda (dat value)
               (add_osc_value_to_payload value dat))
             data
             values)
      (llvm_send_udp (cstring host) port data (i64toi32 msgsize)))))

;; tests

(io:osc:start-server 7020 "osc-echo-on-7020")

(define (osc-echo-on-7020 timestamp address . args)
  (println)
  (println 'received: address '-> args)
  (println '-----------))


($ (send_osc_msg 'localhost' 7020 '/osc/test'
                 (List (OscInt 1)
                       (OscInt 2)
                       (OscFloat 3.0)
                       (OscString 'Four'))))

($ (send_osc_msg 'localhost' 7020 '/osc/test'
                 (List (OscString 'Bye')
                       (OscString 'Bye')
                       (OscString 'Blackbird'))))



Andrew Sorensen

unread,
Oct 20, 2017, 2:50:43 AM10/20/17
to extemp...@googlegroups.com
Also Toby, you'll need to check out HEAD

Cian

unread,
Oct 20, 2017, 8:48:03 AM10/20/17
to extemp...@googlegroups.com
Hi Andrew,

> The slightly more complicated answer is that for many internal operations we
> don't actually care if the data is signed or unsigned, this is true for
> multiplication, addition and subtraction. We also support a number of
> conversion routines with support for unsigned variants: ui64tod for example
> converts unsigned i64 to double and dtoui64 to go back. Nonetheless,
> unsigned is a second class citizen at best, and we should do better :)

I figured it was probably something like that. I'll update the documentation to
clarify this, and throw in some references to conversion routines. If you're ok
with this, I may also note that this will be addressed at some point in the
future.

> ADTs: First thing, you found a bug, thanks :) It's now fixed in HEAD.
> ADTs in XTLang are brand spanking new and are guaranteed to have some
> teething problems. To my knowledge you are only the second person to
> actually try to use them :)

I figured that this was a little bleeding edge... Next week I may have some
questions about typeclasses :) ADTs and typeclasses - two of my favourite
things...

> I think the examples below (and the bug fix) will answer all your question.
> Note that you'll need to latest from git for this to work.

These examples are great, thanks. I'll work some of these into the
documentation.
With a note that they're currently not production ready, but this is being
addressed.

Toby Gifford

unread,
Oct 20, 2017, 9:28:11 PM10/20/17
to extemp...@googlegroups.com
Nice!  My Variant library and OSC stuff is working fine, but this is much more elegant. Are you imagining that sometime in the future the Abstract Data Types will all be superseded by these Algebraic Data Types?

Andrew Sorensen

unread,
Oct 20, 2017, 9:36:19 PM10/20/17
to extemp...@googlegroups.com
Toby, in the sense that libs/core/adt.xtm will be rewritten using algebraic data types, yes.

Andrew Sorensen

unread,
Oct 20, 2017, 9:37:36 PM10/20/17
to extemp...@googlegroups.com
Mind you, most other libs will also get a substantial rewrite at that point also.  the mythical v1.0 ;-)

Toby Gifford

unread,
Oct 20, 2017, 9:39:23 PM10/20/17
to extemp...@googlegroups.com
Oh frabjous day

Toby Gifford

unread,
Oct 20, 2017, 11:09:09 PM10/20/17
to extemp...@googlegroups.com
Speaking of long compile times, should I expect HEAD to take a long time to compile? It's been sitting on 
Evaluating expression: (impc:aot:compile-xtm-file "libs/base/base.xtm")
for quite some time, not sure if it's stuck or thinking
Reply all
Reply to author
Forward
0 new messages