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
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
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
> 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
And usually we would call this 'liftMatr' or something along
these lines. The function "lifts" one function from one domain
to another one.
--
Felipe.
..and then
> reMatr a = (Matr .) ((flip (.) unMatr) a)
> reMatr a = (Matr .) $ (flip (.) unMatr) a
> reMatr = (Matr .) . (flip (.) unMatr)
--
Felipe.
The correct point free version would be :
> reMatr = (Matr .) . (. unMatr)
--
Jedaï
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
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
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
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)
_______________________________________________
> 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
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.