[Haskell-cafe] [] vs [()]

Jonathan Cast jonathanccast at fastmail.fm
Fri Oct 10 14:30:09 EDT 2008


On Fri, 2008-10-10 at 11:14 -0700, Daryoush Mehrtash wrote:
> 
>         I don't think any clarity is added by made-up notation.  I
>         think you
>         mean
> In fact I was "trying" to be correct on this.

Great!

>  Is it wrong to show:
> 
> [()] >> f = f
> 
> as was doing:
> 
> [()]  map f = [f]

Yes.  Juxtaposition is always application in Haskell, and is always
left-associative, and binds more tightly than any other operator.  So
your left-hand side means [()] applied to two arguments, map and f.
This is not legal Haskell, because [()] is not a function.  You intended
to apply the function map to two arguments, f and [()].  The notation
for that is

  map f [()]

so, making that change, you get

  map f [()] = [f]

This is still wrong:

  map :: (a -> b) -> [a] -> [b]

so if

  f :: (() -> b)

then

 map f [()] :: [b]

but if

  f :: (() -> b)

then

  [f] :: [() -> b]

Unification of these types (required for an equation between the two
terms) proceeds as follows:

   [b] = [() -> b]
so b = () -> b

But the unifier doesn't have a rule to solve recursive equations on
types like the above; so unification fails; your rule isn't even
well-typed.

The correct rule is

  map f [()] = [f ()]

where

  f () :: b

so

  [f ()] :: [b]

so everything type-checks.

(>>) is different from map in three ways:

(1) The arguments are in a different order.  It's a minor issue, but of
course you have to get it right.
(2) >> is an infix operator (syntactically distinct from functions: map
and (>>) are functions while `map` and >> are infix operators).  So you
can use it in the middle of your left-hand side.
(2) (>>) has some subtle differences from map.  The definitions are,
roughly:

  map f xn = xn >>= \ x -> return (f x)

  xn >> ys = xn >>= \ x -> ys

map does something interesting with the elements of its argument list:
it passes them to the function f (it also builds a list of the result,
which (>>) leaves to its second argument).  (>>) just ignores those
elements.  This difference is reflected by the types, as well:

  map :: (a -> b) -> [a] -> [b]

The type variable `a' appears twice, so in (map f xn) you know the
argument to f and the elements of xn are related (in some way).

  (>>) :: [a] -> [b] -> [b]

The type variable `a' appears only once, so in (xn >> ys) the elements
of xn are just ignored; only the list structure matters.
> 
> I want to say map function f over a single element list will yield a
> list of single element, the element being function f.

Haskell does distinguish between a function and the result of applying
that function to an argument, so the element *isn't* actually f --- it's
the result of applying f to an argument.

jcc




More information about the Haskell-Cafe mailing list