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

Recursive mono #263

Merged
merged 6 commits into from
Apr 28, 2023
Merged

Recursive mono #263

merged 6 commits into from
Apr 28, 2023

Conversation

b-studios
Copy link
Collaborator

@b-studios b-studios commented Apr 20, 2023

This is an experiment to lift some restrictions in the mlton monomorphization PR #229

There are many different ways to solve the problem of (mutual) recursion over datatypes / records which are introduced by monomorphization. None is really satisfying.

https://gist.github.com/b-studios/c52a5c7a9cfa6c0021f441d3ac2655a2

Alternative 1

  (fn a => 1 + a,
   fn b => fn c =>
    if b then (#2 (myFun ())) b c else c);

print (Int.toString ((#2 (myFun ())) false 1));

This works, but is suboptimal, since ALL block member selections need to be translated to first "force". I don't like it, but it is the only solution so far, that actually works...

Alternative 2

Here is another version of the same idea, but it does not require to change any use sites:

  fun left self = (case (self ()) of
    (l, r) => l
  );
  fun right self = (case (self ()) of
    (l, r) => r
  );
  fun makeFun () = (fn a => 1 + a, fn b => if b then (right makeFun) b else false);
in makeFun () end;

print (Bool.toString ((#2 myFun) false));

It only requires to redefine the extractors locally (since they need to force self). However, it does not work in MLton (and also variants) since myFun will not be generalized.

Also local function definitions will not be generalized.

Alternative 3

This does also not work:

  (fn a => 1 + a,
   fn b => fn c =>
    if b then (#2 (makeFun ())) b c else c);

val myFun = makeFun ();

print (Int.toString ((#2 myFun) false 1));

Due to let generalization failing on myFun. Annotating explicitly gives:

Error: out/experiment.sml 6.5-6.9.
  Type of variable cannot be generalized in expansive declaration: myFun.
    type: _ * (_ -> ['a] -> ['a])
    in: val 'a myFun: ((int -> int) * (bo  ...  > 'a))) = makeFun ()

makeFun () is not a value and does not follow the value restriction! It does not know that it is pure, which would be an alternative to the value restriction..

Summary

So in the end, it looks like we can only go with Alternative 1 which is implemented in this PR.

Here is a very small and preliminary nano benchmark to check that this encoding does not massively lead to performance problems:

https://gist.github.com/b-studios/59d48fb4873341d7c64cc4f57ded953d

@b-studios b-studios changed the base branch from master to evidence-mono April 20, 2023 19:57
@b-studios b-studios mentioned this pull request Apr 28, 2023
@b-studios b-studios marked this pull request as ready for review April 28, 2023 16:44
@b-studios b-studios merged commit a3e765a into evidence-mono Apr 28, 2023
2 checks passed
@b-studios b-studios deleted the recursive-mono branch April 28, 2023 16:52
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

Successfully merging this pull request may close these issues.

None yet

1 participant