-
Notifications
You must be signed in to change notification settings - Fork 643
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
Type check / compilation: a basic problem #2423
Comments
I believe the problem is caused by "too much"* reduction in the types. Deferring the definition makes the variable abstract in the meantime, which prevents reduction. [*] The definition of "too much" here is "I don't like how much time it takes on my computer". The algorithm is most probably correct and making it more efficient is probably a hard problem and I have no idea what the rules/heuristics should be. This is a (reasonably) minimal failing example: -- First, define something exponentially-big-typed
-- along with some utility functions to talk about it.
data Exp : Nat -> Type where
EZ : Exp 1
ES : Exp n -> Exp (n + n)
exp : Nat -> Nat
exp Z = 1
exp (S n) = exp n + exp n
mkExp : {n : Nat} -> Exp (exp n)
mkExp {n = Z} = EZ
mkExp {n = S n} = ES (mkExp {n = n})
------------
-- Now, we define some size constant. 2^20 seems to be enough.
size : Nat
-- size = 20 -- ### uncomment this to make typechecking slow ###
-- At this point of elaboration, the value of `size` is not known
-- and it's probably an opaque/abstract/irreducible value.
--
-- However, the types don't need `size` to reduce in order to match.
bigTypedVal : Exp (exp size)
bigTypedVal = mkExp {n = size}
-- Now we're free to give a concrete value to `size`
-- because it will no longer be reduced.
size = 20
-- However, if `size` were fully defined *before* elaborating
-- the type of `bigTypedVal`, it would reduce to an exponentially-sized type. On my computer, the difference is instantaneous typechecking vs. a runaway program that I have to kill before it eats my memory. If we could teach the typechecker to recognise whether we need to reduce something for typechecking or whether it will typecheck without reducing, we could improve its performance. Can we at least figure out some rules that humans could use to work around this? |
Making |
Making it abstract probably affects only exports, |
I have commited a new version of with
The idea is that the implementor of |
I have a possibly-related issue; I found this one when searching for a related existing issue report so it seems appropriate to report here. With Idris 0.9.20, the following program takes at-least linear time (in the size of the I'm not sure how to apply "%freeze" annotations to the program, but I'm messing with it now and I'll post an update if I figure anything out.
|
I did some benchmarking on three variants of your program:
The benchmarking script ran Surprisingly enough, the lazy variant is only marginally faster than the strict variant, and both are much faster than your version. |
Thanks for doing the extra analysis, Ziman. I did suspect that the
... which still appeared to run in super-linear time... |
It's probably the big |
An exponential fits these curves well (about 3s . 2^(N/1000)), which supports the |
With 0.9.20.1-git:140d06a I can "idris --check" both
and
in constant time in |
Right, so we could regard these issues as the same problem: some things are better left abstract for typechecking (but some are not). |
I think this is a duplicate of #172, which is already tagged as a major issue and put for release |
@ahmadsalim I am not sure that #2418 or even this issue are duplicates of #172. There are similarities (in both cases, deferring a definition helps circumventing a strange compile-time behavior) but I suspect that the causes of such behavior could be different in the two issues. I have constructed another example that might help clarifying what is going on here: on a fresh installation of
This should yield something like
Now, try commenting out line 182
of
You should now get something like
The example shows that type checking certain expressions under the premise that
can cost significantly more than type checking the same expressions under the (weaker!) premise
This behavior seems to violate the (quite reasonable, I think) understanding that stronger assumptions should make type checking easier. What are the expressions on which type checking stumbles when the definition of Using emacs' idris-mode, it is easy to see (by tracking coloring times) that -- when the definition of This is a bit bizarre since lines 192-196 seem very similar to lines 186-190 which type check really fast! The example also suggests that, here, the problem could be quite different than in #172 where type checking time was found to be linear (instead of constant) in Please, let me know if you want me to open a new issue with this specific example. |
@nicolabotta I think the underlying issue is the same, which is that too much reduction is happening in the types. Of course it comes in a different facade than the one in #172, but I think it would be nice if we could have a particular focused issue. If you feel strongly about it, I am more than happy to reopen this issue however. |
The program
https://github.com/nicolabotta/SeqDecProbs/blob/master/frameworks/14-/SeqDecProbMonadicTheoryRVExample2.lidr
type checks and compiles in roughly linear time in
maxColumnO2
.maxColumnO2
is defined at line 94. The times it takes to compile the application formaxColumnO2
equal to 5, 10, 20, 40, 80 and 160 on my machine are:respectively. For larger values of
maxColumnO2
the machine starts swapping and compilation does not appear to terminate. Thus, compiling the application for realistic values ofmaxColumnO2
is virtually impossible. In contrast, the programhttps://github.com/nicolabotta/SeqDecProbs/blob/master/frameworks/14-/SeqDecProbMonadicTheoryRVExample2b.lidr
type checks and compiles in about 50 seconds, independently of the value of
maxColumnO2
. The difference between the two programs is just the point of definition ofmaxColumnO2
: in the second example, this is at line 566.Thus, it seems that the point of definition of parameters can have a dramatic impact on the time it takes to type check or compile a program. This is a serious problem. It implies that developers have to be careful to defer parameter definitions or otherwise accept erratic type check and compile time behavior. Deferring definitions not only leads to spaghetti-code. It also makes the development of sizeable applications very tedious.
I believe that issue #2418 is an instance of the same problem but I do not have a simple solution for that case.
I guess the problem is related with the way reduction operates. The question is whether is is possible to inhibit reduction of certain expressions in certain scopes. This seems to be what happens when the definition of
maxColumnO2
is deferred to line 566.The text was updated successfully, but these errors were encountered: