-
Notifications
You must be signed in to change notification settings - Fork 145
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
foldlM/foldrM doesn't work with Maybe and other pure monads #357
Comments
Interestingly, the following does work:
Could be worth a look what's the difference between
|
And it seems it's not module MyFold where
myFoldM :: (b -> a -> Maybe b) -> b -> [a] -> Maybe b
myFoldM f z (x:xs) = f z x >>= \acc -> myFoldM f acc xs
myFoldM _ z [] = pure z
main = print $ myFoldM (\r _ -> Just $! succ r) 0 [1..5000]
Tracing
Looking at the generated Java code, it looks like final public static <a, b> PreludeBase.TMaybe<b> myFoldM(
final Func.U<b, Func.U<a, PreludeBase.TMaybe<b>>> arg$1, final Lazy<b> arg$2, final PreludeBase.TList<a> arg$3
) {
final PreludeBase.TList.DCons<a> $7643 = arg$3.asCons();
if ($7643 != null) {
final PreludeBase.TList<a> µ$$7591 = $7643.mem2.call();
return Maybe.IMonad_Maybe.<b, b>$gt$gt$eq(
arg$1.apply(arg$2).call().apply($7643.mem1).call(),
(Func.U<b, PreludeBase.TMaybe<b>>)((final Lazy<b> arg$7645) -> {
final b acc$7585 = arg$7645.call();
return Thunk.<PreludeBase.TMaybe<b>>shared(
(Lazy<PreludeBase.TMaybe<b>>)(() -> MyFold.<a, b>myFoldM(
arg$1, Thunk.<b>lazy(acc$7585), µ$$7591
))
);
})
).call();
}
final PreludeBase.TList.DList<a> $7647 = arg$3.asList();
assert $7647 != null;
return Maybe.IApplicative_Maybe.<b>pure(arg$2);
} Note that the return type of If we assume that
So if we can make the generated java method returns myFoldM f z (x:xs) = f z x >>= \acc -> myFoldM f acc xs
myFoldM _ z [] = undefined
main = print $ myFoldM (\r _ -> Just $! succ r) 0 [1..5000] final public static <a, b> Lazy<PreludeBase.TMaybe<b>> myFoldM(
final Func.U<b, Func.U<a, PreludeBase.TMaybe<b>>> arg$1, final Lazy<b> arg$2, final PreludeBase.TList<a> arg$3
) {
...
It does reach the end condition and triggers |
@Ingo60 |
And, in Haskell, foldlM (\r _ -> Just $! succ r) 0 [1..] runs (infinitely) with a constant memory usage. So I'd like to consider this as a compatibility issue. (OTOH, |
There is also the problem that currently, lambdas will have to return |
There must be two reasons for stack overflow, actually:
We can go a bit farther with:
But still:
|
@Ingo60 can't reproduce (stackoverflows with |
Yeah, right, I've given 2m for the repl:
|
It still crashes at 5000 iterations or so with foldlM (\r _ -> case succ r of x | traceLn (show x) -> undefined; !x -> Just x) 0 [1..10000]
foldlM (\r _ -> Just $! succ (if traceLn (show r) then undefined else r)) 0 [1..10000] Both prints digits before crashing, so Also the following crashes too. foldlM (\r _ -> Just 0) 0 [1..10000] |
I suspect that the cause is that |
You're on the right track, as always, @matil019 Maybe.>>= is ok, though. But the compiler's estimation whether |
This thing keeps disturbing me. It would be not enough to enforce the policy that if the tail call returns Lazy, so does the caller. This would only help in the case of But in the case of Maybe I should revise this decision, as most of this code is, in fact, not polymorphic anyway, and thus the performance degradation will not be so big. Another possibility is to think about ways to say: this function (or class method) must return lazy. Maybe some sort of pragma. We will need such a mechanism anyway for different reasons: Currently there are 3 hacks that do something that would be appropriate for pragmas:
Items 2 and 3 are undocumented and exclude each other. So this would be a reason to introduce pragma syntax (like in Haskell), and then we could have
|
Have you measured the difference of run-time between strict vs lazy returns? Performance-intensitive code should not be using polymorphic constructs anyway (unless indirections are resolved in compile time like templates in C++), so if the difference is not too big, it may be acceptable. Also, currently some of generated Java code contains something like As for syntax, here is what I had tried on instinct (and failed): foo :: a -> a
?foo ?a = a
inline bar :: a -> b -> a
inline bar a _ = a Since we annotate each function for public/protected/private instead of module headers, I think it's reasonable to put |
Do you have an example ready where the compiler generates something of the form
This doesn't look right, indeed. |
The following code results in StackOverflowError:
foldrM
has a similar problem.Either
,[]
cause StackOverflowError, too.Meanwhile,
IO
doesn't suffer from this:Workaround
UPDATE Having an
undefined
case changes the return type of Java method toLazy
, so the following seem to work for both finite and infinite lists (only forMaybe
):The text was updated successfully, but these errors were encountered: