Rating \ _ & # 8594; undefined in Haskell

I read this http://www.haskell.org/haskellwiki/Hask . I am struggling with this part.

undef1 = undefined :: a -> b undef2 = \_ -> undefined 

And why they behave like that.

 seq undef1 () = undefined seq undef2 () = () undef2 () = undefined 

What is the reason for this? I would like to understand this behavior, but I donโ€™t even know where to start. In particular, why does undef2 behave differently under strict evaluation?

+7
source share
4 answers

The special function seq evaluates its first argument in the form of a weak head and then returns its second argument. A good explanation of WHNF can be found here , but for the purposes of this answer, I just use the Wiki Haskell definition :

A weak head expression (WHNF) if it:

  • constructor (ultimately applied to the arguments) e.g. True, Just (square 42) or (:) 1
  • a function applied to arguments that are too small (perhaps not relevant), for example (+) 2 or sqrt.
  • or the expression lambda abstraction \ x โ†’.

The important point is that when the expression is a constructor, seq looks only at the constructor tag. So seq (Just undefined) 1 evaluates to 1 .

Another important point is that all types in Haskell are raised - that is, evaluating the type value can lead to an infinite loop or an exception (usually with error or undefined ). After we evaluate seq ab , we can be sure that evaluating a on WHNF will not result in an infinite loop or exception.

Armed with this knowledge, let's look at your example:

 undef1 = undefined :: a -> b undef2 = \_ -> undefined 

When seq undef1 () is evaluated, seq first tries to figure out which of the three categories above undef1 belongs. But undef1 is undefined , so the whole expression evaluates to undefined .

However, in the case of seq undef2 () = () , the first argument is the lambda abstraction. Since seq cannot see the past lambda, it returns the second argument.

The third example, undef2 () = undefined , is simply the direct result of evaluating the application (\_ -> undefined) () .

+9
source

This is not the same thing. undef1 is a function from a to b, but which function is undefined. Evaluating undef1 for normal form gives you undefined.

undef2 is a function from a to b. In particular, it is a function that ignores its argument and returns undefined. But undef2 is not undefined. Only when you try to evaluate a function (as in the third line) do you get undefined. Therefore, when you evaluate undef2 to head the normal form, you get the correct function, not undefined.

To introduce it into more imperative terms (always a source of inaccuracy, but if you are more familiar with this, this illustrates the point well), think of undef1 as a getter property that never returns. (In Haskell, they are not returned and undefined are semantically equivalent.) Undef2 is a getter property that returns a function; This is a function that will not return if you call it. In C #:

 Func<Object, Object> Undef1 { get { while (true) {} return null; } } Func<Object, Object> Undef2 { get { return _ -> { while (true) {} return null; } } } 

Now your tests will become:

 var x = Undef1; var y = Undef2; var z = Undef2(null); 
+3
source

For this question, let's say that there are three things that can make you actually value the value:

  • Pattern matching for this value
  • Applying a Value to an Argument
  • Using it as the first argument to seq

The actual situation is a little more complicated, but not so important.

In addition, this coercion occurs only in the context of any external expression, therefore, instead of thinking of it as a โ€œforced evaluationโ€ in some abstract way, it helps to think of them as an evaluation of an external expression, depending on the evaluation of this values. That is why, for example, seq xx in any sense does not force x , since this is the final value of the expression anyway; he says that when evaluating an external expression (whose value is x ), it must also evaluate x , which is redundant.

Finally, any value that depends on the forced value of undefined is itself undefined.


Passing each expression:

 seq undef1 () = undefined 

In this case, undef1 is undefined, and seq undef1 x is an expression whose value is x and depends on the evaluation of undef1 . Thus, the expression as a whole is undefined, regardless of what the second argument to seq .

 seq undef2 () = () 

In this case, undef2 not undefined, but the result of its application. seq undef2 x is an expression whose value is x and depends on the evaluation of undef2 . This is not a problem, and the first argument to seq discarded, so the value of expression () here.

 undef2 () = undefined 

In this case, we directly apply undef2 . The expression undef2 () depends on the evaluation of undef2 (this is good) and is evaluated with the result of applying undef2 , which in this case is undefined .

Compare this to the fourth case:

 undef1 () = undefined 

In this case, we use undef1 , so the value of the expression depends on the evaluation of undef1 , which is undefined, and therefore the whole expression is the same. This is the same value as the previous expression using undef2 , but for a completely different reason!

+3
source

Well, just write a shorter answer than the others: in order to force an expression of type fx to be evaluated, Haskell first needs to figure out which function is f , and then apply its x . In more technical terms, when fx forced, f must be forced.

Let's get back to your definitions now:

 undef1 :: a -> b undef1 = undefined undef2 :: a -> b undef2 = \_ -> undefined 

Forcing undef1 and undef2 gives different results. Forcing undef1 immediately outputs undefined , while forcing undef2 creates a thunk, which when applied to some argument creates undefined .

I suspect you do not understand what seq does; I get the impression that you think that seq undef2 () should apply undef2 to () , but that is not the case. What seq :: a -> b -> b does is force its first argument and return the second. The difference between seq undef1 () and seq undef2 () is only that only the second will be able to force its first argument, but then it just returns () .

If I'm right about your intention with the code above, then you are looking for ($!) :: (a -> b) -> a -> b , which applies its first argument to the second and forces the result. Thus, both of them do not work with undefined :

 undef1 $! () undef2 $! () 
+3
source

All Articles