List comprehensions (ZF-expressions) with zero qualifiers

176 views Asked by At

List comprehensions (or ZF-expressions) include a sequence of qualifiers, which can be generators or Boolean-valued expressions ("filter expressions") acting as guards.

A list comprehension with no qualifier – for instance, [1 | ] – is (apparently) valid in Miranda1 (p. 130), but is invalid in Haskell2, 3 (p. 42) –I tried it in the ghci interpreter– and is (apparently) invalid in Clean4.

(Of course, we could simulate it by adding a True guard, for instance [1 | True]. But this is more verbose.)

An example of use of a list comprehension with no qualifier in the literature1 (pp. 134-136) is the following instance of equational reasoning:

[E | ] ++ L = [E] ++ L = (E:[]) ++ L = E:L

Why did Haskell and Clean programming language designers decide against list comprehensions without qualifiers? Is there something that would cause bad feature interactions in these languages but not in Miranda?


References:

  1. Simon L. Peyton Jones. The Implementation of Functional Programming Languages. Prentice Hall. 1987.

  2. The Haskell 98 Report, section 3.11 "List Comprehensions". 1998.

  3. Peter Wentworth. An Introduction to Functional Programming Using Hugs. 2013.

  4. Rinus Plasmeijer; Marko van Eekelen; John van Groningen. Clean Language Report, version 2.2. 2011.

1

There are 1 answers

0
K. A. Buhr On

I think the obvious answer is that there is no technical reason to disallow list comprehensions with an empty sequence of qualifiers. The requirement is a purely syntactic one. It just so happens that the original Haskell98 report section 3.11 specifies a grammar that requires the list of qualifiers to be non-empty, and the translation rules to turn it into a kernel expression assume this is the case. GHC obeys this grammar, so an expression like [ 10 | ] is rejected with a parse error.

From a technical standpoint, simply relaxing the grammar and adding a single translation rule:

[ e | ] = [ e | True ]

would address this.

In fact, the documentation for the GHC MonadComprehensions extension actually provides a translation for this case:

[ e | ] = return e

and the rest of the translation rules basically assume that cases of the form:

[ e | q, Q ]

apply to the special case:

[ e | q ]

with Q taken to be empty.

Once you get past the parser, the rest of GHC handles this special case just fine. In particular, if you use Template Haskell to bypass the parser and construct a comprehension with no qualifiers, you can see that it evaluates as expected. (The separate modules here are needed because of the TH phase restricution.)

--
-- EmptyComprehension.hs
--

module EmptyComprehension where

import Language.Haskell.TH

-- equivalent to "[ 10 | ]"
x :: ExpQ
x = compE [noBindS (litE (integerL 10))]


--
-- Test.hs
--

{-# LANGUAGE TemplateHaskell #-}

import EmptyComprehension

main = print $(x)  -- will print `[10]`

As for why the language was designed this way, I imagine it was either an oversight or perhaps it was considered at some point but the syntax [10 | ] was thought to be too bizarre to allow.

On a related note, empty cases were also disallowed by the original Haskell98 report but then permitted via an EmptyCase extension when it was discovered that they could actually be useful.

I think you might have trouble convincing anyone that a similar extension for comprehensions is worthwhile. In the comments, you mention automatic source generation, but it's easy to handle that case specially or add an extra True qualifier to every comprehensive (or -- if you're generating source via TemplateHaskell -- just bypass the restriction directly).