For Programmers: Free Programming Magazines  


Home > Archive > Functional > April 2007 > Confusing Haskell errors in lambda/curried expressions









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Confusing Haskell errors in lambda/curried expressions
Xcriber51

2007-04-11, 8:03 am

Hi --


A few minor questions:

* In the following expression, how do we write a purely curried version of
the lambda expresion in the middle :

sum (map (\n -> (-1)^(n+1) * 3*n) [1..10])

? No matter what I tried, I couldn't get beyond this:

(* ((* 3) . ((-1) ^) . (+ 1)) x) x

(where "x" is one of the numbers in the 1..10 range), but this requires
repeating the number which beats my purpose of using a single curried
expression instead of a lambda.

Am I being pointless?


* I want to filter a list based on two predicates: <gt x and lt y>. But
"filter" doesn't seem to accept more than one predicate:

filter (<=50) . map (^2)) [1..m]

I tried, naively, i) composition ii) disjunctive like so:

filter ((>=15) . (<=50)) . map (^2)) [1..m]
filter ((>=15) && (<=50)) . map (^2)) [1..m]

neither of which worked. Why not?


* In LISP/Scheme, I can write

(expt 2 (- 3))

and get, as expected:

1/8

In Haskell, I get

Program error: Prelude.^: negative exponent

Why?


Thanks in advance.


-- Ken


wagner.andrew@gmail.com

2007-04-11, 7:04 pm

On Apr 11, 7:19 am, "Xcriber51" <xcriber@[OMITTED]> wrote:
> Hi --
>
> A few minor questions:
>
> * In the following expression, how do we write a purely curried version of
> the lambda expresion in the middle :
>
> sum (map (\n -> (-1)^(n+1) * 3*n) [1..10])
>
> ? No matter what I tried, I couldn't get beyond this:
>
> (* ((* 3) . ((-1) ^) . (+ 1)) x) x
>
> (where "x" is one of the numbers in the 1..10 range), but this requires
> repeating the number which beats my purpose of using a single curried
> expression instead of a lambda.
>
> Am I being pointless?


If you visit #haskell on irc.freenode.net, lambdabot is a great tool
for this kind of thing:
@pl \n -> (-1)^(n+1) * 3*n -- get a pointfree version
(*) =<< (3 *) . (subtract 1 ^) . (1 +)

>
> * I want to filter a list based on two predicates: <gt x and lt y>. But
> "filter" doesn't seem to accept more than one predicate:
>
> filter (<=50) . map (^2)) [1..m]
>
> I tried, naively, i) composition ii) disjunctive like so:
>
> filter ((>=15) . (<=50)) . map (^2)) [1..m]
> filter ((>=15) && (<=50)) . map (^2)) [1..m]
>
> neither of which worked. Why not?


With regards to your first attempt, think about function composition:
(.) :: forall b c a. (b -> c) -> (a -> b) -> a -> c
That is, the result of the second function should be the type needed
for the first. But it doesn't make sense to ask whether a boolean is
>=15. Thus, (>=15) . (<= 50) doesn't make sense. Similarly, for the

second attempt,
(&&) :: Bool -> Bool -> Bool
but you're trying to use it as if it had type (Num a,b) => (a -> Bool)
-> (b -> Bool) -> Bool

Here are a couple of versions that work:
filter (liftM2 (&&) (>= 15) (<= 50)) $ map (^2) [1..10]
filter (\n -> (n>=15) && (n<=50)) $ map (^2) [1..10]

>
> * In LISP/Scheme, I can write
>
> (expt 2 (- 3))
>
> and get, as expected:
>
> 1/8
>
> In Haskell, I get
>
> Program error: Prelude.^: negative exponent
>
> Why?
>
> Thanks in advance.
>
> -- Ken


Haskell's mathematical type hierarchy is a little weird, but this
should work:
2 ** (- 3)


Hope this helps.
Andrew

Xcriber51

2007-04-11, 7:04 pm

Thanks, Andrew.

I'll check the IRC group for that factility which looks like a
time-saver.

BTW I think I've realized what I was trying to get at with my erroneous
use of function composition with "filter". As you say, since the output of
the first predicate is a boolean, there's nothing to test for numerically.
But I *could* have coded it like this -- and it would have worked:

(filter (>=15) . filter (<=50)) (map (^2) [1..m])

And indeed it does.

One more thing -- another mystery. Here's a funny (probably not terribly
smart) way of coding the Fibonacci series -- based on the property that
the series is very close to : given phi (1.618), then phi^0 phi^1 phi^2...
phi^n.

filter (<=50) (map (\x -> round (1.618^x)) [0..])

This, however, fails with a "Program error: arithmetic overflow" in Hugs.
In which original way am I being stupid this time :) ?

Cheers


-- Ken



Ben Bacarisse

2007-04-11, 7:04 pm

"Xcriber51" <xcriber@[OMITTED]> writes:

<snip>
> One more thing -- another mystery. Here's a funny (probably not terribly
> smart) way of coding the Fibonacci series -- based on the property that
> the series is very close to : given phi (1.618), then phi^0 phi^1 phi^2...
> phi^n.
>
> filter (<=50) (map (\x -> round (1.618^x)) [0..])
>
> This, however, fails with a "Program error: arithmetic overflow" in Hugs.
> In which original way am I being stupid this time :) ?


Because 1.618^x eventually overflows. Even if floating-point
numbers were not limited in this way, the program would eventually run
out of resources after printing 47.

You know, but Hugs does not, that the sequence is monotonic and that
after finding a number > 50, no more will be forthcoming. Hugs must
just keep trying ever larger xs just in case!

--
Ben.
Dirk Thierbach

2007-04-11, 7:04 pm

Xcriber51 <xcriber@[omitted]> wrote:
> A few minor questions:


> * In the following expression, how do we write a purely curried version of
> the lambda expresion in the middle :
>
> sum (map (\n -> (-1)^(n+1) * 3*n) [1..10])


You need a combinator that "distributes" an argument to two different
functions. For example the following:

($$) :: (a -> b, a -> c) -> a -> (b,c)
(f,g) $$ x = (f x, g x)

Then you can write

*Main> sum $ map (uncurry (*) . (((*3),((-1)^).(+1)) $$)) [1..10]
-15

> Am I being pointless?


I guess at least that example shows that point-free notation can
easily become completely unreadable beyond some point :-)

For readability, list comprehensions are IMHO a lot better:

sum [(-1)^(n+1) * 3*n | n <- [1..10]]

If you really want to be pointless, you can try to write ($$)
in point-free fashion using only the predefined Haskell functions...

> * I want to filter a list based on two predicates: <gt x and lt y>. But
> "filter" doesn't seem to accept more than one predicate:
>
> filter (<=50) . map (^2)) [1..m]


Same problem. You need to apply both predicates to the same argument,
and then form the disjunction (assuming that you want to filter for
those results where both predicates are true):

*Main> filter (uncurry (&&) . (((>=15),(<=50)) $$)) $ map (^2) $ [1..10]
[16,25,36,49]

Again, compare with the list comprehension:

[r | n <- [1..m], let r = n^2, 15 <= r && r <= 50]

> * In LISP/Scheme, I can write
>
> (expt 2 (- 3))
>
> and get, as expected:
>
> 1/8
>
> In Haskell, I get
>
> Program error: Prelude.^: negative exponent
>
> Why?


Because there are two functions for exponentiation, with slightly
different typeclasses:

(^) :: forall a b. (Integral b, Num a) => a -> b -> a
(^^) :: forall a b. (Integral b, Fractional a) => a -> b -> a

The latter can handle negative exponents, but has the additional
requirement that the type "a" must not only be a number, but a
fractional number (i.e., the type must support division).

*Main> :t 2 ^^ (-3)
2 ^^ (-3) :: forall a. (Fractional a) => a

*Main> 2 ^^ (-3)
0.125

If you want a rational result, you have to specify the types accordingly,
or construct the base with the correct type:

*Main> :m Ratio
Prelude Ratio> (2%1) ^^ (-3)
1 % 8

- Dirk
Paul Rubin

2007-04-11, 7:04 pm

"Xcriber51" <xcriber@[OMITTED]> writes:
> filter (<=50) (map (\x -> round (1.618^x)) [0..])
>
> This, however, fails with a "Program error: arithmetic overflow" in Hugs.
> In which original way am I being stupid this time :) ?


Use takeWhile instead of filter.
Dirk Thierbach

2007-04-11, 7:04 pm

wagner.andrew@gmail.com <wagner.andrew@gmail.com> wrote:
> On Apr 11, 7:19 am, "Xcriber51" <xcriber@[OMITTED]> wrote:


> If you visit #haskell on irc.freenode.net, lambdabot is a great tool
> for this kind of thing:
> @pl \n -> (-1)^(n+1) * 3*n -- get a pointfree version
> (*) =<< (3 *) . (subtract 1 ^) . (1 +)


Hm.

Prelude> :t \n -> (-1)^(n+1) * 3*n
forall a. (Integral a) => a -> a

Prelude> :t (*) =<< (3 *) . (subtract 1 ^) . (1 +)
forall a. (Monad ((-> ) (a->a)), Num a, Integral (a->a)) => (a -> a) -> a -> a

A typo somewhere? Using (=<< ) for this sort of trick would be
nice, but I don't see how yet.

- Dirk
Dirk Thierbach

2007-04-11, 7:04 pm

Dirk Thierbach <dthierbach@usenet.arcornews.de> wrote:
> Prelude> :t (*) =<< (3 *) . (subtract 1 ^) . (1 +)
> forall a. (Monad ((-> ) (a->a)), Num a, Integral (a->a)) => (a -> a) -> a -> a
>
> A typo somewhere?


Found it: One needs "(-1)" instead of "subtract 1". Bug in the
printing function?

> Using (=<< ) for this sort of trick would be nice, but I don't see
> how yet.


Found this, too: One needs the partially applied function monad
instance from Control.Monad.Reader. Not so nice. Any alternatives?

> - Dirk

Xcriber51

2007-04-12, 4:04 am

Thanks to everyone who has provided explanations, solutions, and
suggestions.

I realize some of my attempts were not entirely "honorable" towards
Haskell ;-P but you see, I'm trying to learn its intricacies, so I'm
looking for ways to push the proverbial envelope, so excuse the point-free
syntactic "gullible's travels."

If you have any further suggestions for the above - like those umpteen
variants of factorial I saw on a web site - please don't be shy :)


Cheers
-- Ken

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com