Forcing evalation in the IO Monad

Hi folks, This question is so trivial it must have been answered before, but I have been googling all morning to no avail so please bear with me. I've been wading through mires of $! and seq, deepSeq, $!! etc.. and I have leaned a lot of useful stuff about lazy evaluation - but I haven't been able to solve my problem.. What I would like to do is to force an expression to be fully evaluated to normal form, from inside the IO monad, right there and then. For example, in GHCI, calling putStrLn does just what I want: Debug.Trace Prelude> let a = trace "Hello" 42 Debug.Trace Prelude> putStrLn $ show a Hello 42 Except that it only takes showable things, and it puts an annoying message on the screen. What I want is something like putStrLn that doesn't print anything, and takes any type as its input, evaluates it to normal form and then does nothing else. It might be called something like 'evaluate' have a type like this evaluate :: a -> IO() It _must_ exist - and it _must_ be easier to find this sort of thing than I am making it, or else how did all you haskell gurus attain your status? Am I missing something :) All the best, Philip

Philip Scott wrote:
What I want is something like putStrLn that doesn't print anything, and takes any type as its input, evaluates it to normal form and then does nothing else. It might be called something like 'evaluate' have a type like this
evaluate :: a -> IO()
With Hoogle, you can search for types: http://haskell.org/hoogle/?hoogle=a+-%3E+IO+%28%29 12th result from the top. Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

Am Freitag 16 April 2010 16:25:08 schrieb Heinrich Apfelmus:
Philip Scott wrote:
What I want is something like putStrLn that doesn't print anything, and takes any type as its input, evaluates it to normal form and then does nothing else. It might be called something like 'evaluate' have a type like this
evaluate :: a -> IO()
With Hoogle, you can search for types:
http://haskell.org/hoogle/?hoogle=a+-%3E+IO+%28%29
12th result from the top.
That evaluates only to WHNF. Control.DeepSeq.rnf seems to be closer, but requires NFData instances.
Regards, Heinrich Apfelmus

Daniel Fischer wrote:
Am Freitag 16 April 2010 16:25:08 schrieb Heinrich Apfelmus:
Philip Scott wrote:
What I want is something like putStrLn that doesn't print anything, and takes any type as its input, evaluates it to normal form and then does nothing else. It might be called something like 'evaluate' have a type like this
evaluate :: a -> IO()
With Hoogle, you can search for types:
http://haskell.org/hoogle/?hoogle=a+-%3E+IO+%28%29
12th result from the top.
That evaluates only to WHNF.
Control.DeepSeq.rnf seems to be closer, but requires NFData instances.
The documentation says that, but it does appear to go deeper than just one level: Debug.Trace Prelude Control.Exception> let a = trace "Hello" 42 Debug.Trace Prelude Control.Exception> let b = trace "Frank" (a * 2) Debug.Trace Prelude Control.Exception> evaluate b Frank Hello 84 Perhaps it specifies WHNF in case you 'evaluate' something which doesn't have a HNF (like a partially applied function?). - Philip

Philip Scott wrote
The documentation says that, but it does appear to go deeper than just one level:
Debug.Trace Prelude Control.Exception> let a = trace "Hello" 42 Debug.Trace Prelude Control.Exception> let b = trace "Frank" (a * 2) Debug.Trace Prelude Control.Exception> evaluate b Frank Hello 84
Perhaps it specifies WHNF in case you 'evaluate' something which doesn't have a HNF (like a partially applied function?).
It is actually quite interesting what it does in this case:
let f x = trace "jingle" (x * 2) a <- evaluate (f) :t f f :: (Num a) => a -> a :t a a :: Integer -> Integer
So it does some sort of evaluation - it has decided we're going to be using Integers instead of Nums. I wonder what it is up to there.

Am Freitag 16 April 2010 17:09:07 schrieb Philip Scott:
Philip Scott wrote
The documentation says that, but it does appear to go deeper than just one level:
Debug.Trace Prelude Control.Exception> let a = trace "Hello" 42 Debug.Trace Prelude Control.Exception> let b = trace "Frank" (a * 2) Debug.Trace Prelude Control.Exception> evaluate b Frank Hello 84
Perhaps it specifies WHNF in case you 'evaluate' something which doesn't have a HNF (like a partially applied function?).
It is actually quite interesting what it does in this case:
let f x = trace "jingle" (x * 2) a <- evaluate (f)
:t f
f :: (Num a) => a -> a
:t a
a :: Integer -> Integer
So it does some sort of evaluation - it has decided we're going to be using Integers instead of Nums. I wonder what it is up to there.
Without impredicative polymorphism (whatever that is), you can't get a polymorphic value from an action, so while Prelude Debug.Trace Control.Exception> :t evaluate f evaluate f :: (Num a) => IO (a -> a) , when you bind the result of evaluate f to a name, that is assigned a monomorphic type. Without a type signature, the type variable a is defaulted to Integer. You can (until 6.14) Prelude Debug.Trace Control.Exception> :set -XImpredicativeTypes Prelude Debug.Trace Control.Exception> u <- evaluate f :: IO (forall a. Num a => a -> a) <no location info>: Warning: -XImpredicativeTypes is deprecated: impredicative polymorphism will be simplified or removed in GHC 6.14 Prelude Debug.Trace Control.Exception> :t u u :: (Num a) => a -> a Prelude Debug.Trace Control.Exception> u 4 :: Int jingle 8 Prelude Debug.Trace Control.Exception> u 4 :: Double jingle 8.0 Prelude Debug.Trace Control.Exception> u 4 :: Rational jingle 8 % 1

Am Freitag 16 April 2010 17:00:57 schrieb Philip Scott:
The documentation says that, but it does appear to go deeper than just one level:
Debug.Trace Prelude Control.Exception> let a = trace "Hello" 42 Debug.Trace Prelude Control.Exception> let b = trace "Frank" (a * 2) Debug.Trace Prelude Control.Exception> evaluate b Frank Hello 84
Perhaps it specifies WHNF in case you 'evaluate' something which doesn't have a HNF (like a partially applied function?).
Prelude Control.Exception> let lst = [undefined,undefined] :: [Bool] Prelude Control.Exception> evaluate lst >>= putStrLn . take 1 . show [ Prelude Control.Exception> evaluate lst >>= print [*** Exception: Prelude.undefined Prelude Control.Exception Debug.Trace> let a = trace "Hello" 42 Prelude Control.Exception Debug.Trace> let b = trace "Frank" [a] Prelude Control.Exception Debug.Trace> evaluate b Frank [Hello 42] Prelude Control.Exception Debug.Trace> let a = trace "Hello" 42 Prelude Control.Exception Debug.Trace> let b = trace "Frank" [a] Prelude Control.Exception Debug.Trace> evaluate b >>= print . null Frank False a is only evaluated when it's needed for printing here. For most number types, weak head normal form is already normal form. You can only spot the difference on types with more than one constructor or a lazy field in a constructor.
- Philip

Prelude Control.Exception> let lst = [undefined,undefined] :: [Bool] Prelude Control.Exception> evaluate lst>>= putStrLn . take 1 . show [ Prelude Control.Exception> evaluate lst>>= print [*** Exception: Prelude.undefined
Ahh, yes you are of course right. Hmm so, how do we crack this nut without resorting to deepSeq etc.. It must be possible, because it happens when you print it! Am I going to have to resort to physically writing the output to /dev/null ? It seems like such an ordinary thing to want to do, the fact that it is hard makes me think I must be approaching this in the wrong way (which is usually the case when I get my knickers in a twist with Haskell ;) - Phil

Am Freitag 16 April 2010 20:50:21 schrieb Philip Scott:
Prelude Control.Exception> let lst = [undefined,undefined] :: [Bool] Prelude Control.Exception> evaluate lst>>= putStrLn . take 1 . show [ Prelude Control.Exception> evaluate lst>>= print [*** Exception: Prelude.undefined
Ahh, yes you are of course right. Hmm so, how do we crack this nut without resorting to deepSeq etc.. It must be possible, because it happens when you print it!
When you print it, show demands that the value be completely evaluated. If the data-dependencies require an expression to be completely evaluated, it will be done. And that's basically the only way to get expressions evaluated. 'seq' and its relatives only give you a means to introduce new (artificial) data-dependencies.
Am I going to have to resort to physically writing the output to /dev/null ?
I think deepseq/rnf from Control.DeepSeq and NFData instances may be easier than writing stuff to /dev/null.
It seems like such an ordinary thing to want to do,
Not really. Wanting something to be completely evaluated without a direct need from data-dependencies is something not too ordinary in a lazy language. Of course, you sometimes need it, that's why there are seq and NFData. But it remains something special.
the fact that it is hard makes me think I must be approaching this in the wrong way (which is usually the case when I get my knickers in a twist with Haskell ;)
- Phil

Philip Scott wrote:
Daniel Fischer wrote:
Am Freitag 16 April 2010 16:25:08 schrieb Heinrich Apfelmus:
Philip Scott wrote:
What I want is something like putStrLn that doesn't print anything, and takes any type as its input, evaluates it to normal form and then does nothing else. It might be called something like 'evaluate' have a type like this
evaluate :: a -> IO()
With Hoogle, you can search for types:
http://haskell.org/hoogle/?hoogle=a+-%3E+IO+%28%29
12th result from the top.
That evaluates only to WHNF.
Control.DeepSeq.rnf seems to be closer, but requires NFData instances.
The documentation says that, but it does appear to go deeper than just one level:
Debug.Trace Prelude Control.Exception> let a = trace "Hello" 42 Debug.Trace Prelude Control.Exception> let b = trace "Frank" (a * 2) Debug.Trace Prelude Control.Exception> evaluate b Frank Hello 84
Perhaps it specifies WHNF in case you 'evaluate' something which doesn't have a HNF (like a partially applied function?).
"evaluate x" is defined as "return $! x". This indeed evaluates the value immediately then and there. It *only* evaluates to WHNF (weak head normal form). For number values, WHNF (= evaluate to outer constructor only) and NF (= completely evaluate) are the same thing, as shown in your example above. The (a * 2) makes no difference, because whether WHNF = NF or not depends on the type of the value only, not the expression used to calculate it. To evaluate x to NF (completely) then and there in general, you have to say evaluate (rnf x) where rnf is defined in Control.DeepSeq in the 'deepseq' package. The type of x has to be an NFData instance. Haskell does not provide any other way to force evaluation to NF other than to explicitly use `seq` on each element of the structure. The purpose of DeepSeq is to make this task easier. Steve

Am Freitag 16 April 2010 21:14:54 schrieb Stephen Blackheath [to Haskell- Beginners]:
"evaluate x" is defined as "return $! x".
Not quite: Prelude Control.Exception> evaluate (undefined :: Int) `seq` True True Prelude Control.Exception> ((return $! undefined) :: IO Int) `seq` True *** Exception: Prelude.undefined Haddocks: "Forces its argument to be evaluated to weak head normal form when the resultant IO action is executed. It can be used to order evaluation with respect to other IO operations; its semantics are given by evaluate x `seq` y ==> y evaluate x `catch` f ==> (return $! x) `catch` f evaluate x >>= f ==> (return $! x) >>= f Note: the first equation implies that (evaluate x) is not the same as (return $! x). A correct definition is evaluate x = (return $! x) >>= return "
This indeed evaluates the value immediately then and there. It *only* evaluates to WHNF (weak head normal form). For number values, WHNF (= evaluate to outer constructor only) and NF (= completely evaluate) are the same thing, as shown in your example above. The (a * 2) makes no difference, because whether WHNF = NF or not depends on the type of the value only, not the expression used to calculate it.
To evaluate x to NF (completely) then and there in general, you have to say
evaluate (rnf x)
where rnf is defined in Control.DeepSeq in the 'deepseq' package. The type of x has to be an NFData instance. Haskell does not provide any other way to force evaluation to NF other than to explicitly use `seq` on each element of the structure. The purpose of DeepSeq is to make this task easier.
Steve

All, Philip's original question was:
This question is so trivial it must have been answered before, but I have been googling all morning to no avail so please bear with me. I've been wading through mires of $! and seq, deepSeq, $!! etc.. and I have leaned a lot of useful stuff about lazy evaluation - but I haven't been able to solve my problem.. What I would like to do is to force an expression to be fully evaluated to normal form, from inside the IO monad, right there and then.
For example, in GHCI, calling putStrLn does just what I want:
Debug.Trace Prelude> let a = trace "Hello" 42 Debug.Trace Prelude> putStrLn $ show a Hello 42
Except that it only takes showable things, and it puts an annoying message on the screen.
Daniel - I get what you're saying... Daniel Fischer wrote:
Am Freitag 16 April 2010 21:14:54 schrieb Stephen Blackheath [to Haskell- Beginners]:
"evaluate x" is defined as "return $! x".
Not quite:
Prelude Control.Exception> evaluate (undefined :: Int) `seq` True True Prelude Control.Exception> ((return $! undefined) :: IO Int) `seq` True *** Exception: Prelude.undefined
I'll explain the difference for the benefit of beginners: For IO actions that take arguments, there are two steps involved in executing them in IO: 1. evaluate it to value of type "IO a", and 2. sequence it, which is a general monad term, but in the IO monad it means that it will be actually executed. IO actions that don't take arguments, like getLine, just go straight to step 2. For example, if you have 'putStrLn name', then 1. Evaluate: Apply the argument name (type: String) to putStrLn (type: String -> IO ()). This gives a value of type IO (). This is plain old ordinary pure Haskell function evaluation. 2. Sequence: The action embodied in the IO () value is actually executed, and the name appears on the screen. The difference between the two ways of forcing evaluation are, therefore: "return $! x" does the forcing when it is evaluated. "evaluate x" does the forcing when it is sequenced. Since sequencing demands evaluation anyway, in all practical situations these are equivalent. But "evaluate x" works more like what you would expect: "evaluate (rnf x)" is exactly analogous to "putStrLn (show x)" except without the screen output. Steve

Heinrich Apfelmus wrote:
Philip Scott wrote:
What I want is something like putStrLn that doesn't print anything, and takes any type as its input, evaluates it to normal form and then does nothing else. It might be called something like 'evaluate' have a type like this
evaluate :: a -> IO()
With Hoogle, you can search for types:
http://haskell.org/hoogle/?hoogle=a+-%3E+IO+%28%29
12th result from the top.
Genius indeed! At least I had the right type, and even the right name.. :) Thanks ever so much. - Philip
participants (5)
-
Daniel Fischer
-
Heinrich Apfelmus
-
Philip Scott
-
Philip Scott
-
Stephen Blackheath [to Haskell-Beginners]