Haskell has a magical function named seq, which takes an argument of any type and reduces it to Weak Head Normal Form (WHNF).
I’ve read a couple of sources [not that I can remember who they were now…] which claim that “polymorphic seq is bad”. In what way are they “bad”?
Similarly, there is the rnf function, which reduces an argument to Normal Form (NF). But this is a class method; it does not work for arbitrary types. It seems “obvious” to me that one could alter the language spec to provide this as a built-in primitive, similar to seq. This, presumably, would be “even more bad” than just having seq. In what way is this so?
Finally, somebody suggested that giving seq, rnf, par and similars the same type as the id function, rather than the const function as it is now, would be an improvement. How so?
As far as I know a polymorphic
seqfunction is bad because it weakens free theorems or, in other words, some equalities that are valid withoutseqare no longer valid withseq. For example, the equalityholds for all functions
g :: tau -> tau', all listsxs :: [tau]and all polymorphic functionsf :: [a] -> [a]. Basically, this equality states thatfcan only reorder the elements of its argument list or drop or duplicate elements but cannot invent new elements.To be honest, it can invent elements as it could “insert” a non-terminating computation/run-time error into the lists, as the type of an error is polymorphic. That is, this equality already breaks in a programming language like Haskell without
seq. The following function definitions provide a counter example to the equation. Basically, on the left hand sideg“hides” the error.In order to fix the equation,
ghas to be strict, that is, it has to map an error to an error. In this case, the equality holds again.If you add a polymorphic
seqoperator, the equation breaks again, for example, the following instantiation is a counter example.If we consider the list
xs = [False, True], we havebut, on the other hand
That is, you can use
seqto make the element of a certain position of the list depend on the definedness of another element in the list. The equality holds again ifgis total. If you are intereseted in free theorems check out the free theorem generator, which allows you to specify whether you are considering a language with errors or even a language withseq. Although, this might seem to be of less practical relevance,seqbreaks some transformations that are used to improve the performence of functional programs, for example,foldr/buildfusion fails in the presence ofseq. If you are intereseted in more details about free theorems in the presence ofseq, take a look into Free Theorems in the Presence of seq.As far as I know it had been known that a polymorphic
seqbreaks certain transformations, when it was added to the language. However, the althernatives have disadvantages as well. If you add a type class basedseq, you might have to add lots of type class constraints to your program, if you add aseqsomewhere deep down. Furthermore, it had not been a choice to omitseqas it had already been known that there are space leaks that can be fixed usingseq.Finally, I might miss something, but I don’t see how a
seqoperator of typea -> awould work. The clue ofseqis that it evaluates an expression to head normal form, if another expression is evaluated to head normal form. Ifseqhas typea -> athere is no way of making the evaluation of one expression depend on the evaluation of another expression.