For example:
[n * n | n <- [1..5], even n]
While shorter than using map and filter, it's a specialized syntax. If a
predicate were introduced into normal lambdas, you could get a more concise
result with no special syntax (other than the introduction of predicates):
mapf (\n |even n| -> n * n) [1..5]
A type 'void' would be used to indicate no value, and hence no concatenate.
It could also be used for loop constructs (sorry, destructive operations :)
x = 0
while (|x < 10| -> x = x + 1)
and a replacement for pattern matching:
x = |x > 1| -> 1;
|x < -1| -> -1;
_ -> x
Mike
[1] http://en.wikipedia.org/wiki/List_comprehension#Javascript_1.8
> It seems every language is adopting list comprehensions, even
> JavaScript [1]. I understand its roots, but can it can be done much
> simpler, and without specialized syntax?
>
> For example:
>
> [n * n | n <- [1..5], even n]
>
> While shorter than using map and filter, it's a specialized syntax.
> If a predicate were introduced into normal lambdas, you could get a
> more concise result with no special syntax (other than the
> introduction of predicates):
>
> mapf (\n |even n| -> n * n) [1..5]
>
> A type 'void' would be used to indicate no value, and hence no
> concatenate.
You would probably want to make 'void' a value rather than a separate
type, as the latter would preclude static typing.
Adding void values to all types can be tricky as you need to specify how
all operations behave on void values.
> It could also be used for loop constructs (sorry, destructive operations :)
>
> x = 0
> while (|x < 10| -> x = x + 1)
>
> and a replacement for pattern matching:
>
> x = |x > 1| -> 1;
> |x < -1| -> -1;
> _ -> x
You can indeed do so, and list comprehensions are typically translated
into combinations of maps and filters -- sometimes with subsequent
optimisation, but not necessarily so.
As you note, this requires closures to be implemented in the language.
You suggest adding predicates to lambdas so they define partial
functions (i.e., may be undefined) and define mapf etc. so they skip
undefined results. Many functional languages allow patterns or guards
in anonymous functions. Haskell (which allows both) has no mechanism
for catching the undefined cases -- it would just stop with an error
message, but Standard ML (which has patterns but not guards on lambdas)
throws an exception that can be caught by a function like mapf. But in
both cases it is more common to do one of:
1. Separate the test and operation into two functions, so you first use
the test to filter out unwanted elements and then apply the
operation to the rest.
2. Make a combined test-and-operate function return a value that is
either NONE or SOME(v), where v is the result. A function like mapf
can then ignore the NONE values and construct a list of the SOME
values. NONE and SOME are usually implemented so NONE is a null
value and SOME(v) is a non-null value v.
Note that you can translate list comprehensions to code that doesn't use
closures, so you can add them to languages that don't allow true
functional values.
Torben
Or, as you state below, use Just and Nothing correct?
As you can probably tell, I'm not a heavy user of functional languages. I
thank you for being so clear and concise. I finally installed Haskell (hugs)
so I could experiment, but there are a few things I don't quite get.
This is as close as I could get without errors, but it returns
[Just 4,Nothing,Just 16,Nothing], not exactly what I'm looking for.
mapf f [] = []
mapf f (x:xs) = let result = f x in
case result of
Just a -> Just a : map f xs
Nothing -> map f xs
foo = \n -> if even n then Just (n * n) else Nothing
print (mapf foo [1..5])
I would like to construct a list with only "a" in stead of "Just a", but I get
"unification would give infinite type". Also, I don't understand why "Nothing"
is getting prepended to the list.
> Note that you can translate list comprehensions to code that doesn't use
> closures, so you can add them to languages that don't allow true
> functional values.
That's quite true. Wait, there are languages that don't use closures? :)
> Torben
Mike
> As you can probably tell, I'm not a heavy user of functional
> languages. I thank you for being so clear and concise. I finally
> installed Haskell (hugs) so I could experiment, but there are a few
> things I don't quite get.
>
> This is as close as I could get without errors, but it returns
> [Just 4,Nothing,Just 16,Nothing], not exactly what I'm looking for.
>
> mapf f [] = []
> mapf f (x:xs) = let result = f x in
> case result of
> Just a -> Just a : map f xs
> Nothing -> map f xs
>
> foo = \n -> if even n then Just (n * n) else Nothing
>
> print (mapf foo [1..5])
>
> I would like to construct a list with only "a" in stead of "Just a",
> but I get "unification would give infinite type". Also, I don't
> understand why "Nothing" is getting prepended to the list.
This is caused by calling map rather than mapf in the recursive calls.
This is also why the type system forced you to add Just in the RHS of
the first case branch. The following should work:
mapf f [] = []
mapf f (x:xs) = let result = f x in
case result of
Just a -> a : mapf f xs
Nothing -> mapf f xs
foo = \n -> if even n then Just (n * n) else Nothing
print (mapf foo [1..5])
Torben
Oops, I was so focused on the syntax that I missed the details, thanks.
> mapf f [] = []
> mapf f (x:xs) = let result = f x in
> case result of
> Just a -> a : mapf f xs
> Nothing -> mapf f xs
>
> foo = \n -> if even n then Just (n * n) else Nothing
>
> print (mapf foo [1..5])
>
> Torben
I'm beginning to like Haskell - defining operators is very cool:
print $ mapf (\n -> even n ? n * n) [1..10]
Although, as with anything, power comes with responsibility.
----------
module Main where
import System.Environment
True ? x = Just x
False ? _ = Nothing
infix 0 ?
mapf f [] = []
mapf f (x:xs) = let result = f x in
case result of
Just a -> a : mapf f xs
Nothing -> mapf f xs
main = do
print (mapf (\n -> even n ? n * n) [1..10])
Mike