Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: [Haskell-cafe] pointfree-trouble

0 views
Skip to first unread message

Kim-Ee Yeoh

unread,
Dec 22, 2009, 3:50:49 AM12/22/09
to haskel...@haskell.org

Here's another way of writing it:

data Matrix a = Matr {unMatr :: [[a]]} | Scalar a deriving (Show, Eq)
-- RealFrac constraint removed

reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
reMatr f = Matr . f . unMatr -- this idiom occurs a lot, esp. with
newtypes

Affixing constraints to type constructors is typically deprecated.

slemi wrote:
>
> i have trouble making a function pointfree:
>
> data RealFrac a => Matrix a = Matr [[a]] | Scalar a
> deriving (Show, Eq)
>
> unMatr :: RealFrac a => Matrix a -> [[a]]
> unMatr = (\(Matr a) -> a)
>
> reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
> reMatr a = Matr . (flip (.) unMatr) a
>
> this works fine, but if i leave the 'a' in the last function's definition
> like this:
> reMatr = Matr . (flip (.) unMatr)
> it gives an error. can anybody tell me why? (i'm using ghci)
>

--
View this message in context: http://old.nabble.com/pointfree-trouble-tp26881661p26885392.html
Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

slemi

unread,
Dec 22, 2009, 9:09:57 AM12/22/09
to haskel...@haskell.org

hello everybody, i'm a newbie this is my first post here..

i have trouble making a function pointfree:

data RealFrac a => Matrix a = Matr [[a]] | Scalar a
deriving (Show, Eq)

unMatr :: RealFrac a => Matrix a -> [[a]]
unMatr = (\(Matr a) -> a)

reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
reMatr a = Matr . (flip (.) unMatr) a

this works fine, but if i leave the 'a' in the last function's definition
like this:
reMatr = Matr . (flip (.) unMatr)
it gives an error. can anybody tell me why? (i'm using ghci)
--

View this message in context: http://old.nabble.com/pointfree-trouble-tp26881661p26881661.html

slemi

unread,
Dec 22, 2009, 9:13:53 AM12/22/09
to haskel...@haskell.org

thanks, that's a really neat syntactic sugar :)

however, my original question was how to make the reMatr function pointfree,
as


reMatr = Matr . (flip (.) unMatr)

is not working. any ideas/explanation why it doesnt work?


Kim-Ee Yeoh wrote:
>
> Here's another way of writing it:
>
> data Matrix a = Matr {unMatr :: [[a]]} | Scalar a deriving (Show, Eq)
> -- RealFrac constraint removed
>
> reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
> reMatr f = Matr . f . unMatr -- this idiom occurs a lot, esp. with
> newtypes
>
> Affixing constraints to type constructors is typically deprecated.
>
>
>
> slemi wrote:
>>
>> i have trouble making a function pointfree:
>>
>> data RealFrac a => Matrix a = Matr [[a]] | Scalar a
>> deriving (Show, Eq)
>>
>> unMatr :: RealFrac a => Matrix a -> [[a]]
>> unMatr = (\(Matr a) -> a)
>>
>> reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
>> reMatr a = Matr . (flip (.) unMatr) a
>>
>> this works fine, but if i leave the 'a' in the last function's definition
>> like this:
>> reMatr = Matr . (flip (.) unMatr)
>> it gives an error. can anybody tell me why? (i'm using ghci)
>>
>
>

--
View this message in context: http://old.nabble.com/pointfree-trouble-tp26881661p26888978.html

Keith Sheppard

unread,
Dec 22, 2009, 9:28:12 AM12/22/09
to slemi, haskel...@haskell.org
Hello, I didn't try to understand what the function is doing, but just
quickly noticed that

> reMatr a = Matr . (flip (.) unMatr) a

can be written as
> reMatr a = Matr . ((flip (.) unMatr) a)

but that


> reMatr = Matr . (flip (.) unMatr)

can be written as
> reMatr a = (Matr . (flip (.) unMatr)) a

so because of precedence rules a different function is being applied
to 'a' in the 2 versions

Best
Keith

--
keithsheppard.name

Felipe Lessa

unread,
Dec 22, 2009, 9:33:39 AM12/22/09
to haskel...@haskell.org
On Tue, Dec 22, 2009 at 12:50:26AM -0800, Kim-Ee Yeoh wrote:
> reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
> reMatr f = Matr . f . unMatr -- this idiom occurs a lot, esp. with newtypes

And usually we would call this 'liftMatr' or something along
these lines. The function "lifts" one function from one domain
to another one.

--
Felipe.

Felipe Lessa

unread,
Dec 22, 2009, 9:34:59 AM12/22/09
to haskel...@haskell.org
On Tue, Dec 22, 2009 at 09:27:47AM -0500, Keith Sheppard wrote:
> Hello, I didn't try to understand what the function is doing, but just
> quickly noticed that
>
> > reMatr a = Matr . (flip (.) unMatr) a
>
> can be written as
> > reMatr a = Matr . ((flip (.) unMatr) a)

..and then

> reMatr a = (Matr .) ((flip (.) unMatr) a)
> reMatr a = (Matr .) $ (flip (.) unMatr) a
> reMatr = (Matr .) . (flip (.) unMatr)

--
Felipe.

Chaddaï Fouché

unread,
Dec 22, 2009, 9:35:25 AM12/22/09
to slemi, haskel...@haskell.org
On Tue, Dec 22, 2009 at 3:09 PM, slemi <0sl...@gmail.com> wrote:
> this works fine, but if i leave the 'a' in the last function's definition
> like this:
> reMatr = Matr . (flip (.) unMatr)

The correct point free version would be :

> reMatr = (Matr .) . (. unMatr)

--
Jedaï

Daniel Fischer

unread,
Dec 22, 2009, 9:41:56 AM12/22/09
to haskel...@haskell.org
Am Dienstag 22 Dezember 2009 15:09:34 schrieb slemi:
> hello everybody, i'm a newbie this is my first post here..
>
> i have trouble making a function pointfree:
>
> data RealFrac a => Matrix a = Matr [[a]] | Scalar a
> deriving (Show, Eq)
>
> unMatr :: RealFrac a => Matrix a -> [[a]]
> unMatr = (\(Matr a) -> a)
>
> reMatr :: RealFrac a => ([[a]] -> [[a]]) -> (Matrix a -> Matrix a)
> reMatr a = Matr . (flip (.) unMatr) a
>
> this works fine, but if i leave the 'a' in the last function's definition
> like this:
> reMatr = Matr . (flip (.) unMatr)
> it gives an error. can anybody tell me why? (i'm using ghci)

You want

reMatr f = Matr . f . unMatr

= (.) Matr (f . unMatr)
= (.) Matr ((.) f unMatr)
= (.) Matr (flip (.) unMatr f)
= (.) Matr ((flip (.) unMatr) f)
= (((.) Matr) . (flip (.) unMatr)) f

So

reMatr = ((.) Matr) . (flip (.) unMatr)

Or, as I prefer it,

reMatr = (Matr .) . (. unMatr)

The point is that g = flip (.) unMatr [or (. unMatr)] takes two arguments, the function f
and a matrix m, to yield an argument fitting for Matr, so we need to apply one argument
before we can compose it with Matr, hence we compose it with (compose with Matr) = (.)
Matr = (Matr .):

(Matr .) . g

Kim-Ee Yeoh

unread,
Dec 23, 2009, 2:34:12 AM12/23/09
to haskel...@haskell.org

There you have it: fully- and semi-pointfree versions of reMatr.

A heads up: aggressively pursuing pointfreeness without type signatures
guarantees a courtesy call from the monomorphism restriction,
pace ()-garlic aficionados.

As for your question on why the original code doesn't typecheck: if
you explain how you arrived at it, perhaps we can figure out where
you tripped up. Daniel Fischer for instance, *calculated* for you
the right answer. Habeas calculus and all that.

--
View this message in context: http://old.nabble.com/pointfree-trouble-tp26881661p26897626.html

slemi

unread,
Dec 23, 2009, 8:41:09 AM12/23/09
to haskel...@haskell.org

i dont know any calculus-thingy, this is what i did:

reMatr a = Matr . a . unMatr
reMatr a = Matr . (. unMatr) a


reMatr a = Matr . (flip (.) unMatr) a

reMatr = Matr . (flip (.) unMatr)

as http://old.nabble.com/pointfree-trouble-td26881661.html#a26889388 Daniel
pointed out, this doesnt work because (flip (.) unMatr) takes two arguments.
i'm really interested in this calculus stuff, looking up now:)

--
View this message in context: http://old.nabble.com/pointfree-trouble-tp26881661p26902326.html

Daniel Fischer

unread,
Dec 23, 2009, 11:00:24 AM12/23/09
to haskel...@haskell.org
Am Mittwoch 23 Dezember 2009 14:40:46 schrieb slemi:
> i dont know any calculus-thingy, this is what i did:
>
> reMatr a = Matr . a . unMatr
> reMatr a = Matr . (. unMatr) a
> reMatr a = Matr . (flip (.) unMatr) a

You need to be aware of the implicit parentheses, that is

Matr . ((flip (.) unMatr) a)

or

(.) Matr ((flip (.) unMatr) a)

= ((.) Matr) ((flip (.) unMatr) a)

= f (g x), with

f = (.) Matr


g = flip (.) unMatr

x = a

Now f (g x) = (f . g) x and you're done.

But as Kim-Ee Yeoh pointed out, if you're pointfreeing, give type signatures, or the
monomorphism restriction is going to surprise you some time.

> reMatr = Matr . (flip (.) unMatr)

_______________________________________________

Mark Lentczner

unread,
Dec 24, 2009, 6:20:19 PM12/24/09
to Haskell Café
For the record, all of these compile with -O to exactly the same code!

> reMatr1 f m = Matr (f (unMatr m))
> reMatr2 f m = Matr $ f $ unMatr m
> reMatr3 f m = Matr . f . unMatr $ m
> reMatr4 f = Matr . f . unMatr
> reMatr5 f = Matr . (flip (.) unMatr) f
> reMatr6 = (Matr .) . (. unMatr)

And that code is the same as what reMatr1 compiles to with no optimization!

Under no optimization, they all compile to direct implementations of their approach - and hence, reMatr1 is the most efficient. The others must wend through quite a number of library functions to do their work.

Since there is no real efficiency issue (surely matrix manipulation code will be compiled -O for actual use), the only reason I can see to choose one of these over the other is how it conveys the intention from one programmer to the next. (Or one's self six months later...) In which case seems to me that reMatr4 most cleanly encapsulates the programmer's intention. Of course, I've had some Haskell experience and I get the idiom - to someone less versed in Haskell, reMatr1 is probably the clearest - to someone with much Haskell experience, perhaps reMatr6, though it just looks "clever" to me, rather than clear.

I'm curious why the original poster was motivated to pursue pointfree style to the point of no explicit arguments?

- Mark

Daniel Fischer

unread,
Dec 24, 2009, 7:01:54 PM12/24/09
to haskel...@haskell.org
Am Freitag 25 Dezember 2009 00:19:58 schrieb Mark Lentczner:
> For the record, all of these compile with -O to exactly the same code!
>
> > reMatr1 f m = Matr (f (unMatr m))
> > reMatr2 f m = Matr $ f $ unMatr m
> > reMatr3 f m = Matr . f . unMatr $ m
> > reMatr4 f = Matr . f . unMatr
> > reMatr5 f = Matr . (flip (.) unMatr) f
> > reMatr6 = (Matr .) . (. unMatr)
>
> And that code is the same as what reMatr1 compiles to with no optimization!
>
> Under no optimization, they all compile to direct implementations of their
> approach - and hence, reMatr1 is the most efficient. The others must wend
> through quite a number of library functions to do their work.

Yes, GHC doesn't inline across module boundaries without optimisations.

>
> Since there is no real efficiency issue (surely matrix manipulation code
> will be compiled -O for actual use), the only reason I can see to choose
> one of these over the other is how it conveys the intention from one
> programmer to the next. (Or one's self six months later...) In which case
> seems to me that reMatr4 most cleanly encapsulates the programmer's
> intention.

I think so, too. Version 1 is fine, too. Version 2 could be okay if the function had a
longer name than f, as it is, the f is squashed by the two adjacent $s. Version 3 is not a
good point to stop on the way from 1 to 4 IMO.

> Of course, I've had some Haskell experience and I get the idiom
> - to someone less versed in Haskell, reMatr1 is probably the clearest - to
> someone with much Haskell experience, perhaps reMatr6, though it just looks
> "clever" to me, rather than clear.

It's easy enough to understand with sufficient experience, and among the completely
pointfree versions, I think it's the clearest (also clearer than version 5, although
that's not yet completely point free). But although it's fairly benign, it already shows
that completely pointfree style tends to obfuscate except in the simplest cases.

>
> I'm curious why the original poster was motivated to pursue pointfree style
> to the point of no explicit arguments?

I can't speak for the OP, but pointfreeing is always an interesting mental exercise, it's
often fun to push it deep into obfuscation just for the heck of it.
But, more importantly, you learn to understand the combinators better, and you develop a
sense of how far to go with pointfreeing.


0 new messages