Topics

Random Numbers?

Scott Rostrup
 

Hey Patrick, this is Scott, I'll meet you on Tuesday :)

Really like what you are doing here!  Read through the whole learning by example guide and I kept jotting down questions as I read and then they would be answered later, really like the guide, it seems essential for getting started.


Quick question on random numbers, for my first solo program I wanted to make some random floating point numbers for testing.  I can find the rand() function wrapped from C in the core, but srand isn't wrapped so I always get the same set of numbers and can't reseed, and then I need to convert everything to float anyway and rand() is kind of crap in any case.  Do you have some other random number libraries wrapped somewhere already?  Or is this still an open work in progress? 

If it's not done, I'd be interested to wrap one, maybe this one http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html ?  I haven't looked into rngs recently, that one came high on google.

 

Eager to meet you on Tuesday Scott!

Good point. We need to wrap up seed and float-rand still. If you know of some good implementations that are appropriate for general-purpose use (i.e. isn't overly inefficient), let us know! The one you linked to seems pretty good.

  -Patrick

Scott Rostrup
 

Since what I'd like to do is try out Stanza some more, I think I'll follow your self-hosting approach and implement the mersenne twister in stanza itself :)

 

Sounds fun! Please share your code after you're done!

Scott Rostrup
 

Accidentally promised to show this at our reading group meeting on Friday so I just hammered it out from the pseudo code on wikipedia, https://github.com/sarostru/doggerel/blob/master/examples/mersenne.stanza

Really impressed that the pseudo code pretty much 1-1 translated into stanza :), I still need to go through and make sure it passes the expected randomness distribution checks and add some sanity tests.  After that, it could be interesting to try and improve it's performance and make it more useful.


What suggestions would you have on how to refactor?  I know from other examples about how to encapsulate the state into it's own instance of a type, but other than that are there other features that might improve performance?  e.g I noticed in the reference that there is a ByteArray type that sounds like it could be helpful.


 

Hi Scott!

The code is very readable! We designed Stanza to resemble our own pseudo-code so we we're glad that the experience translates over. I can't really see anything in the code that needs improvement. The one tiny improvement I can see is that Stanza does support hexadecimal numbers. So you can write the following directly:

    val a = 0x9908B0DF

-Patrick

Scott Rostrup
 

Thanks Patrick, nice didn't realize I could write the hex directly.


I was wondering about some of the wrapped functions in the core, for instance sqrt, https://github.com/StanzaOrg/lbstanza/blob/master/core/core.stanza#L6067 , I couldn't find any defmulti sqrt, but they seem to behave like multimethods, what is happening here?

I was also struggling a bit with trying to use the type inference mechanism, in the examples they are all like this:

defn myfunc<?T> (L:List<?T>):

  ...

does this mean, the <?T> style inference should only be used when the function body is universally polymorphic but not when it is ad-hoc polymorphic?  (I'm using the terminology from the diagram on page 4 of Luca and Cardelli, http://lucacardelli.name/papers/onunderstanding.a4.pdf )  

 

The sqrt function in core is actually an example of function overloading, not multimethods. A multimethod has only a single static type: the only declared using the defmulti keyword. When a multimethod is called, at runtime, execution dispatches to the appropriate code.

Function overloading, deals with a set of (potentially unrelated) functions, each with its own type. Stanza's resolver can determine which function you mean to call by examining its context.

And you're right, type variables (as used in your myfunc example) is for universal polymorphism. The defmulti/defmethod system is what you would use for ad-hoc polymorphism.

-Patrick

Scott Rostrup
 

Thanks Patrick!  That clarifies things for me, I was conflating the multimethods and the overloading.  

Scott Rostrup
 

Hopefully last question on the function typing, thanks for your patient answers Patrick :)

 
I think ultimately the real thing I've been wanting to do is write functions that have the same bodies but could take either Float or Double, e.g.

defn F (x:Double) -> Double:
    x * x - 3.0

defn F (x:Float) -> Float:
    x * x - 3.0f


And then I'm trying to do something like I might do in C++ to have it compile different versions for different types, e.g.

<template T>

T F(T x) { return x * x - 3.0;}


I've tried a lot of different ways to unify the function body with no luck, I was about to investigate the macro-utils package in more detail, but before I did that I thought I would ask about this particular use-case.


 

Hi Scott.

Unfortunately what you're trying to do (easily define a bunch of overloaded functions) is not yet supported. You'll have to type it out manually for now. We are going to add another macro to the core library that will simplify this process so that you can write something like the following:

#for (T in [Int, Double, Float], V in [3, 3.0, 3.0f]) :
  defn myfunc (x:T) -> T :
    x * x - V

Hope that helps.

  -Patrick

Scott Rostrup
 

Cool, thanks for explaining.  My aim at the moment isn't to achieve any particular thing, but mostly just to explore the wonderful language you've created here, so I hope you don't mind the questions.  I really like how you've mapped these different abstract concepts (overloading, multimethods, universal polymorphism) onto explicit language constructs in such a direct way.

I may give the multiple overloaded function definition implementation a shot myself with the existing macros since I'd like to learn more about using them, I'll post back with how that goes :)

- Scott

 

Not at all. Please ask questions as they arise. It will save you some time and also help us improve our documentation.

And the macro system is not documented yet, so you're definitely jumping off the deep end there. But it will be up soon.

  -Patrick

Scott Rostrup
 

Great, I'll keep the docs in mind as I go.  For the macros, I got an S-expression filled in pretty easily with fill-template, but as to what to do with it after that I was at a bit of a loss.  I grepped for an eval function, but no such luck :)

Any pointers on where I should look?

 

Hi Scott.


That's great. Now you're hitting upon less documented parts. The next thing you need to do is to extend the compiler with your new macro and produce a staged compiler.

Here's an example. Suppose that I have a macro called 

    plus-three(x) 

that I want to expand into 

    x + 3

. Then in our file mymacros.stanza, we will include the following:

    defpackage mymacros :
      import core
      import macro-utils
      import stz/core-macros
    defsyntax mylang :
      import exp4 from core
      defrule exp4 = (plus-three(?e:#exp)) :
         val expanded = qquote(~ e + 3)
         parse-syntax[core / #exp](expanded)

To extend our compiler, we would then have to type the following:

    stanza mymacros.stanza STANZADIR/stz-main.stanza -o exstanza

And then you have a new extended compiler called exstanza that will recognize mylang.

    #use-added-syntax(mylang)
    defn f (x:Int) :
       plus-three(x)

Which you can compile using

    exstanza myprog.stanza -o myprog

The process is a little cumbersome right now, and we're in the process of streamlining it. The current flow is geared towards making it possible to write very difficult macros, rather than making it effortless to write easy macros.

  -Patrick

Scott Rostrup
 

Thanks for the simple run down, this is exactly what I was looking for.  I did run into a snag trying to compile your demo, so with the exact code I hit this error,

$ stanza mymacros.stanza ../../lbstanza/compiler/stz-main.stanza -o exstanza

> In syntax package mylang: Could not resolve production exp.


It's a bit confusing because I can see that exp is defined in the compiler/stz-core-macros.stanza file so I tried a few different variations of listing different files etc to no avail, it did however work if I changed the first `#exp` to `Int` in mymacros.stanza, but then the extended compiler failed on myprog.


Could it be a version problem? I'm using the latest linux brew install (which worked really great btw), but the source code I was pointing at is from master on the github repo.


Thanks,

Scott

 

Oops. I forgot to import exp. Here's the fixed mymacros.stanza.

defpackage mymacros :
  import core
  import macro-utils
  import stz/core-macros
  
defsyntax mylang :
  import (exp, exp4) from core
  defrule exp4 = (plus-three(?e:#exp)) :
     val expanded = qquote(~ e + 3)
     parse-syntax[core / #exp](expanded)

This is compiled using

stanza tests/mymacros.stanza STANZADIR/stz-main.stanza -o exstanza

to produce the extended compiler exstanza.

And here's a sample program myprog.stanza that uses the new language.

#use-added-syntax(mylang)
defn f (x:Int) :
   plus-three(x)
println(f(10))

You can compile this program using

    exstanza myprog.stanza -o myprog

And when you run myprog, it should print out

13

Hope that helps!

  -Patrick

Scott Rostrup
 

Thanks for that, that seems to work now, should have thought of trying that.  It's a little bit confusing that in the previous stanza programs I didn't have to explicitly list the imports from a package but for the macros you do (always?).  What is the interpretation of the hash, #, how should I read it?

I'm helping facilitate global day of code retreat on Saturday, http://globalday.coderetreat.org/ , I'll see if I can get some stanza takers :)

Actually, someone did an interesting concurrent go implementation of the game of life using goroutines a few years back (https://github.com/amscanne/golang-async-life), could be interesting to try with stanza's coroutines, hmm.  



 

Hey Scott.

For the macro system, you have to explicitly import the different productions individually. The hash, #, is the syntax for specifying a production. The following rule says that:

defrule exp4 = (plus-three(?e:#exp))

The pattern plus-three(?e:#exp) will match against call to plus-three containing a single expression argument. Within the body of the macro, the expression is bound to e. So the following forms are examples of forms that will match the pattern:

plus-three(x)
plus-three(x + y)
plus-three(plus-three(3))

And here are some example forms that will not match.

plus-three(x, y)
plus-three()
plus-three(3 4)

Stanza's coroutines are pretty powerful. The Game of Life should be a great match for it! 

  -Patrick