Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function with strict arguments

Tags:

haskell

A corrected quiz in my textbook is asking me how many of f's arguments are strict, f being:

f x 0 z = x == z
f x y z = x

My initial thought was that all of f's arguments are to be considered strict, since y is being evaluated to check if its equal to 0, and x and z are compared to see that they're both equal. And yet the answer is that only x and y are strict.

Any clues as to why?

like image 410
Sanzor Avatar asked Feb 10 '21 23:02

Sanzor


2 Answers

First of all, you need a very precise definition of "strict" in order for this to make sense. A function f is strict iff evaluating f x to whnf causes x to be evaluated to whnf. The interaction this has with currying is a bit awkward, and I'm going to ignore some of the potential weirdness that introduces.

Assuming the type here is f :: Bool -> Int -> Bool -> Bool your analysis of the behavior wrt y is correct - evaluating f x y z to whnf will always require evaluating y to determine which equation to choose. As that is the only factor determining which equation to use, we have to split the analysis for x and z. In the first equation, evaluating the result to whnf results in both x and z being evaluated. In the second equation, evaluating the result to whnf results in evaluating x to whnf.

Since x is evaluated in both branches, this function is strict in x. This is a little bit amusing - it's strict in the way id is strict. But that's still valid! z, however, is a different story. Only one of the branches causes z to be evaluated, so it's not evaluated strictly - it's only evaluated on demand. Usually we talk about this happening where evaluation is guarded behind a constructor or when a function is applied and the result isn't evaluated, but being conditionally evaluated is sufficient. f True 1 undefined evaluates to True. If f was strict in z, that would have to evaluate to undefined.

like image 104
Carl Avatar answered Oct 22 '22 17:10

Carl


It turns out that whether f is strict in its second argument depends on what type it gets resolved to.

Here's proof:

data ModOne = Zero
instance Eq ModOne where
    _ == _ = True -- after all, they're both Zero, right?
instance Num ModOne -- the method implementations literally don't matter

f x 0 z = x == z
f x y z = x

Now in ghci:

> f True (undefined :: ModOne) True
True
> f True (undefined :: Int) True
*** Exception: Prelude.undefined

And, in a related way, whether f is strict in its third argument depends on what values you pick for the first two. Proof, again:

> f True 1 undefined
True
> f True 0 undefined
*** Exception: Prelude.undefined

So, there isn't really a simple answer to this question! f is definitely strict in its first argument; but the other two are conditionally one or the other depending on circumstances.

like image 26
Daniel Wagner Avatar answered Oct 22 '22 18:10

Daniel Wagner