Frege / frege

Frege is a Haskell for the JVM. It brings purely functional programing to the Java platform.
https://github.com/Frege/frege/wiki/_pages
Other
3.64k stars 145 forks source link

Polymorphic tail recursion with class context does not work #103

Closed Ingo60 closed 9 years ago

Ingo60 commented 9 years ago

Consider the following:

frege> :{
frege> nested :: Show a => Int -> a -> String
frege> nested 0 x = show x
frege> nested n x = nested (n-1) [x]
frege> :}

function nested :: Show a => Int -> a -> String

frege> nested 0 true
true

frege> nested 1 true
java.lang.ClassCastException: frege.prelude.PreludeBase$TList$DCons cannot be cast to java.lang.Boolean

The reason is that the current implementation of tail calls just updates the arguments on each turn, but not the context. Thus, in the second call, it tries to show a list of Bools by calling the Bool.show function, because the dictionary for Show Bool got passed initially.

Note that the type of the value that is finally shown is a surrounded by n bracket pairs.

The case, while clearly a bug, doesn't seem to be of practical importance, and merely of theoretical interest. Here is a workaround:

frege> :{
frege> nested :: Show a => Int -> a -> String
frege> nested 0 x = show x
frege> nested n x = nested (n-1) [x] ++ ""
frege> :}

function nested :: Show a => Int -> a -> String

frege> nested 2 true
[[true]]

The trick is to remove the tail recursion by applying a function that is the identity on the result. (But don't use id, as this will be removed by the optimizer!)

Ingo60 commented 9 years ago

Fixed in the work23 branch.

Ingo60 commented 9 years ago

Fixed with commit 5a61c533a0913b7fde7d848686395ebb15696542 to be merged into main at a later time.