Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

While loop #50

Open
japanoise opened this issue Dec 17, 2019 · 3 comments
Open

While loop #50

japanoise opened this issue Dec 17, 2019 · 3 comments

Comments

@japanoise
Copy link
Contributor

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
Copy link
Owner

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
Copy link
Contributor Author

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
Copy link
Owner

glycerine commented Dec 17, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants