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!)
Consider the following:
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
Bool
s by calling theBool.show
function, because the dictionary forShow Bool
got passed initially.Note that the type of the value that is finally shown is
a
surrounded byn
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:
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!)