0

Suppose I have a following program:

foo x y = let l1 = foo 0 x
              l2 = foo 0 y
          in l1 + l2

This is just a simple example, but I think is enough for demonstration purposes. How could I, with each new (recursive) call to foo, change the evaluation ordering of the expression in l1 and l2? I know they are evaluated lazy inside the expression (in this case expression inside in operator) and not when they are declared, but I need a way of doing as stated, because there may be cases, where the program enters infinite loop. If this infinite recursion occurs on the secondly evaluated argument, l2, there is no problem, as l1 always gets evaluated before *l2, but if it is the other way around, that is, infinitely evaluating the l1 expression, the *l2***doesn't get a chance to evaluate. So if I could juggle between ***l1* and l2 expression evaluation on each new foo function call, the problem would be solved. Looking for a nice/general solution.

EDIT: Forgot to mantion that x or y or both might be an infinite structures (lists), and thats where the problem is.

user2340939
  • 1,791
  • 2
  • 17
  • 44
  • 2
    If you get stuck in an infinite evaluation, why would it matter where that happens? – chi Feb 07 '15 at 17:21
  • 1
    I'm not sure I understand the problem. `l1` and `l2` and not evaluated lazily in that context. – Shoe Feb 07 '15 at 17:22
  • I'm not sure, I understand your question. Are you saying you have a function that causes an infinite loop and you want to prevent that by changing the evaluation order? If so, that's not possible. The default evaluation order is already strongly normalizing. If a given piece of code (that doesn't change the evaluation order using `seq` or similar constructs) causes an infinite loop, there simply is no evaluation order that would make that code terminate. For example the code in your question can't possibly terminate. – sepp2k Feb 07 '15 at 17:24
  • @chi because if I call my function with some specific parameters, eg. bar x y, it works, but if I call it with bar y x I get *** Exception: <> – user2340939 Feb 07 '15 at 17:28
  • 3
    @user2340939 Maybe you should show your function `bar` then because that's definitely not true of your function `foo` - `foo` will loop no matter what arguments you call it with. – sepp2k Feb 07 '15 at 17:37
  • @user2340939 In that case, it's not a matter of evaluation order, but of having something evaluated in one case and not evaluated in another. – chi Feb 07 '15 at 17:49
  • @chi correct, and I want to evalute l1, then on the next foo call l2, then l1, l2, l1 etc. – user2340939 Feb 07 '15 at 18:03
  • @user2340939 You can add a boolean parameter to your function and then use `if b then doSomethingWith l1 else doSomethingElseWith l2`. In each branch you can perform recursive calls toggling the boolean, so to alternate `l1` with `l2`. – chi Feb 07 '15 at 18:15
  • @chi Yea Im trying similar solution right now, but I want to find "a nice/general solution.". – user2340939 Feb 07 '15 at 18:17
  • 1
    Voting to close because the code posted and problem asserted do not line up. Code exists that exhibits your bug (`bar`) but it is not made available nor does it correlate with `foo` like you seem to think. – Thomas M. DuBuisson Feb 07 '15 at 18:37
  • 1
    There's something wrong with this question as currently posed. It no longer references a `bar` as described in previous comments, but instead does some kind of weird recursive call to `foo`. The problem is `foo :: Num a => [a] -> [a] -> a` but `l1` and `l2` is call `foo` with only a single parameter. It's not at all clear what this question is trying to ask. – cassandracomar Feb 07 '15 at 19:21

1 Answers1

1

The Problem

For a good answer, we first need a specific question. Consider that natural numbers that are either zero Z or the successor S n of another natural number n.

data Nat = Z | S Nat

zero = Z
one  = S Z
two  = S $ S Z

In Haskell we can also write infinite recusive data structures like

infinity = S infinity

As long as a single Nat number isn't infinity we can determine if it is even or odd.

even :: Nat -> Bool
even  Z    = True
even (S n) = odd n

odd :: Nat -> Bool
odd  Z    = False
odd (S n) = even n

For finite Nats, even is either True or False and even infinity is undefined. This is ok, but what if we wanted to check if either of two numbers is even? We can write a naïve implementation:

eitherEven :: Nat -> Nat -> Bool
eitherEven x y = even x || even y

This does quite well whenever the first argument is finite. In the following, even is any even number and odd is any odd number.

eitherEven even even     == True
eitherEven even odd      == True
eitherEven even infinity == True
eitherEven odd  even     == True
eitherEven odd  odd      == False
eitherEven odd  infinity == undefined

But when the first argument is infinite, it doesn't return True even when the second argument is Even

eitherEven infinity even     == undefined -- this should be True
eitherEven infinity odd      == undefined
eitherEven infinity infinity == undefined

A simple solution

A simple solution to the problem is to alternate between testing the first argument and testing the second argument. When we call the function recursively, we swap the arguments to alternate which of the two arguments is being tested.

eitherEven :: Nat -> Nat -> Bool
eitherEven Z         _ = True
eitherEven (S Z)     y = even y 
eitherEven (S (S x)) y = eitherEven y x

This has the desired output even when the first argument isn't finite.

> eitherEven infinity two
True

For more complicated problems where the arguments aren't treated symmetrically, you can pass a Bool flag and flip it on each step. In general you can use any state machine to keep track of where you are working.

This solution isn't very satisfying because it doesn't immediately solve what to do when we want to test if any of three numbers is even. To do so we need to write a new function.

anyEven3 :: Nat -> Nat -> Nat -> Bool
anyEven3 Z         _ _ = True
anyEven3 (S Z)     y z = eitherEven y z
anyEven3 (S (S x)) y z = anyEven3 y z x

We put x at the end because we want to try both y and z before trying x again. We're making a queue. If we can prove that the first thing in the queue produces a result, True, we are done. If we can prove the first thing in the queue doesn't produce a result, we remove it from the queue and use a version that works on a smaller set of inputs. If we can't decide the result for the first thing in the queue, we put it at the end. The same pattern can be seen in eitherEven which takes two arguments and even in even which takes only one argument.

anyEven :: [Nat] -> Bool
anyEven = go []
    where
        go [] [] = False
        go r  [] = go [] (reverse r)
        go r (      Z  :_ ) = True
        go r (    S Z  :ns) = go r     ns
        go r ((S (S x)):ns) = go (x:r) ns
Cirdec
  • 24,019
  • 2
  • 50
  • 100
  • I don't have time to develop this all the way into [one of the general solutions](https://hackage.haskell.org/package/logict) this weekend. – Cirdec Feb 07 '15 at 21:18