While loop
japanoise opened this issue · 3 comments
japanoise commented
It'd be rad to have a while loop construct. I've had to hack it in myself, using this:
func truthyResult(env *zygo.Zlisp, fun *zygo.SexpFunction) (bool, error) {
res, err := env.Apply(fun, []zygo.Sexp{})
if err != nil {
return false, err
}
switch rt := res.(type) {
case *zygo.SexpBool:
return rt.Val, nil
case *zygo.SexpSentinel:
return false, nil
default:
return true, nil
}
}
// While hacks a while loop into zygomys
func While(env *zygo.Zlisp, name string, args []zygo.Sexp) (zygo.Sexp, error) {
if len(args) != 2 {
return zygo.SexpNull, errors.New("Syntax: (while cond body)")
}
var cond, body *zygo.SexpFunction
switch st := args[0].(type) {
case *zygo.SexpFunction:
cond = st
default:
return zygo.SexpNull, errors.New("While loop takes two functions")
}
switch st := args[1].(type) {
case *zygo.SexpFunction:
body = st
default:
return zygo.SexpNull, errors.New("While loop takes two functions")
}
result, err := truthyResult(env, cond)
if err != nil {
return zygo.SexpNull, err
}
for result {
_, err := env.Apply(body, []zygo.Sexp{})
result, err = truthyResult(env, cond)
if err != nil {
return zygo.SexpNull, err
}
}
return zygo.SexpNull, err
}
Is there a better way? Or would this require extending the language?
I'd like to be able to do:
(while (== true cond)
(some)
(body))
glycerine commented
Hi @japanoise that would be pretty cool. Just add a couple of correctness tests to the test suite and file a pull request, and we'll put it in.
japanoise commented
Well, currently the API is too clumsy. I wouldn't put it in as-is.
You have to do e.g.
(while (fn [] (==cond true) (fn [] (body goes here))
I was wondering if you had a macro hack or something to make it nicer.
glycerine commented
The proper way would be to add it to the built in codegen, alongside the for
builtin. You could probably just copy and modify the for
Generator.GenerateForLoop code in generator.go:817 to be like Go and only need the middle test.