Idris is already quite good at optimizing / inlining do blocks for IO (and possibly - with proper inlining - for other monads), but this process can introduce quite a few non-productive artifacts, which makes the generated code less readable and potentially less efficient.
Steps to Reproduce
Compute and run the following program and inspect the generated scheme and JavaScript code:
module Ref
import Data.IORef
%default total
%inline
release : IORef Nat -> IO ()
release ref = pure ()
%inline
readAndRelease : IORef Nat -> IO Nat
readAndRelease ref = do
v <- readIORef ref
release ref
pure v
setget : IORef Nat -> IORef Nat -> IO (Nat,Nat)
setget r1 r2 = do
writeIORef r1 100
x <- readAndRelease r1
y <- readAndRelease r2
pure (x,y)
main : IO ()
main = do
r1 <- newIORef Z
r2 <- newIORef Z
p <- setget r1 r2
printLn p
Observed Behavior
The generated JavaScript for function setget looks as follows:
As can be seen, several lines in the code above are completely redundant. While the introduction of const $d = undefined should be easy to get rid of, the non-productive let bindings (const $8 = $9) are interesting as these should actually be caught during constant folding. Since the JS codegen flattnes and rearranges nested let bindings to a certain degree, it is easier to spot what's going on when inspecting the generated scheme code:
In the code above, we see nested let bindings of the type let x := y in x. These can always be replaced with y, because they are only required for the side-effects being run in y.
Getting rid of these two kinds of artifacts should be straight forward with the already existing constant-folding machinery. I'll open a PR in a moment.
Idris is already quite good at optimizing / inlining
do
blocks forIO
(and possibly - with proper inlining - for other monads), but this process can introduce quite a few non-productive artifacts, which makes the generated code less readable and potentially less efficient.Steps to Reproduce
Compute and run the following program and inspect the generated scheme and JavaScript code:
Observed Behavior
The generated JavaScript for function
setget
looks as follows:As can be seen, several lines in the code above are completely redundant. While the introduction of
const $d = undefined
should be easy to get rid of, the non-productivelet
bindings (const $8 = $9
) are interesting as these should actually be caught during constant folding. Since the JS codegen flattnes and rearranges nestedlet
bindings to a certain degree, it is easier to spot what's going on when inspecting the generated scheme code:In the code above, we see nested
let
bindings of the typelet x := y in x
. These can always be replaced withy
, because they are only required for the side-effects being run iny
.Getting rid of these two kinds of artifacts should be straight forward with the already existing constant-folding machinery. I'll open a PR in a moment.