-
Notifications
You must be signed in to change notification settings - Fork 220
optimize Natural/fold in the strict case #2585
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
optimize Natural/fold in the strict case #2585
Conversation
Co-authored-by: Gabriella Gonzalez <[email protected]>
|
@Gabriella439 Thank you for the suggestion. I'm not sure why the build fails for MacOS. I also have trouble building Update - this is fixed now. |
|
@Gabriella439 My changes do not actually seem to work. I built a local executable ( let f : Natural → Natural = λ(x : Natural) → if Natural/isZero x then 1 else x
in Natural/fold 100000000 Natural f 0takes about 5 seconds but should be instantaneous. Am I doing something wrong? I changed the Dhall version to 1.42.2 in $ stack build dhall
...
Installing executable dhall in /Users/sergei.winitzki/Code/winitzki-dhall-haskell/.stack-work/install/x86_64-osx/5cb58a553262eb646270303a92d2143ba964e30fb089950b829eb0787bd00e99/9.2.8/bin
Registering library for dhall-1.42.2..
$ stack exec dhall repl
Welcome to the Dhall v1.42.2 REPL! Type :help for more information.
⊢ :let f : Natural → Natural = λ(x : Natural) → if Natural/isZero x then 1 else x
f : Natural → Natural
⊢ Natural/fold 100000000 Natural f 0
1This still takes about 5 seconds. How could this even work if I compiled dhall with no code for Am I editing the wrong place in the source code? I see that some code involving |
|
I added some new code to Why is For |
|
@Gabriella439 You merged the PR but I still think the work is not finished. See my comment in the code. |
| in go zero (fromIntegral n' :: Integer) | ||
| go zero (fromIntegral n' :: Integer) where | ||
| go !acc 0 = acc | ||
| go (VNaturalLit x) m = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, we detect the shortcut only when the accumulator is a Natural literal. However, we would like to detect the shortcut in all cases. I could not find any way of comparing Val values. What kind of code would need to be written here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dhall.Eval.conv is what you want
1.42.2 * [Supports standard version 23.1.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v23.1.0) * [Allow `Natural` and `Integer` literals in binary notation](dhall-lang/dhall-haskell#2540) * Fix macOS build [[#2561](dhall-lang/dhall-haskell#2561)] / [[#2586](dhall-lang/dhall-haskell#2586)] * [`dhall to-directory-tree`: Fix support for empty `Map`s](dhall-lang/dhall-haskell#2609) * [`Dhall.TH`: Improve recompilation checking](dhall-lang/dhall-haskell#2620) * `Dhall.TH` utilities now use `addDependentFile` internally so that GHC will recompile if any Dhall dependencies change * Performance improvements * Optimize `Natural/fold`: [[#2585](dhall-lang/dhall-haskell#2585)] / [[#2596](dhall-lang/dhall-haskell#2596)] * [Improve `Dhall.Map.traverseWithKey` performance](dhall-lang/dhall-haskell#2589) * The fold will now short-circuit if it reaches a fixed point * [#2611](dhall-lang/dhall-haskell#2611) * Fixes and improvements to test suite * [#2593](dhall-lang/dhall-haskell#2593) * Fixes and improvements to haddocks * [#2546](dhall-lang/dhall-haskell#2546) * Fixes and improvements to code formatting * [#2608](dhall-lang/dhall-haskell#2608)
The proposed optimization follows the discussion in dhall-lang/dhall-lang#1213 (comment)
The beta-normalization for
Natural/fold n t succ zerocorresponds to evaluatingsucc(succ(succ(...(succ(zero))...)))where we applysuccexactlyntimes.The current code uses a loop where
succis always evaluatedntimes.However, sometimes the loop can be stopped early because the values stop changing.
For example:
With this definition, we have
f x = xwhen x is nonzero. The expression evaluates to 5, but the evaluation takes time linear in the first argument (10000000) because the functionfwill be applied that many times to the value5and beta-normalization will be performed each time.The new code rewrites
strictLoopviastrictLoopShortcut, which stops the loop as soon asf x = x.This optimization is only applied in the "strict" case (
Normalization.hsintroducesstrictandlazycases when evaluatingNatural/fold.)There should be no change of behavior after this optimization.
This is because all Dhall functions are pure; if
f x = xthen the result of evaluatingf (f (f x))is exactly the same as justx.So, the only effect of the new code is that some
Natural/foldexpressions will be beta-normalized faster than before.I'd like to add some tests for the new behavior but I don't know how. The new behavior returns exactly the same normal forms as before, but does it faster when the "shortcut" is detected (when
f x = xis detected). I am not a Haskell programmer, so any suggestions will be welcome here.Another issue is that I am not familiar with the Haskell build systems, and both
cabal new-build dhallas well asstack buildfail on my machine in this project, with dependency errors that I am unable to fix.