Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help in understanding pointfree code

When playing around with Pointfree I was presented with a piece of code that I can't seem to understand.

:pl map (\x -> x * x) [1..10]
-- map (join (*)) [1..10]

My main problem is that I don't get how join works here. I understand that it 'removes' one layer of a monadic wrapping (m (m a) to m a). I figure it boils down to something like [1..10] >>= (\x -> [x * x]), but I don't really get how the "extra layer" gets introduced. I get that join x = x >>= id, but then I'm still stuck on how that "duplicates" each value so that (*) gets two arguments. This has been bugging me for about half an hour now and I'm mostly annoyed at myself, because I feel like I have all the puzzle pieces but can't seem to fit them together...

P.S. Don't worry, I would't really use this pointfree version, this is pure curiosity and an attempt to understand Haskell better.

like image 636
Michael Kohl Avatar asked Jul 22 '11 23:07

Michael Kohl


People also ask

What is point free code?

Tacit programming, also called point-free style, is a programming paradigm in which function definitions do not identify the arguments (or "points") on which they operate. Instead the definitions merely compose other functions, among which are combinators that manipulate the arguments.

What is point free style in Haskell?

Point free style means that the code doesn't explicitly mention it's arguments, even though they exist and are being used. This works in Haskell because of the way functions work.

What is true functional programming?

Functional programming is a programming paradigm in which we try to bind everything in pure mathematical functions style. It is a declarative type of programming style. Its main focus is on “what to solve” in contrast to an imperative style where the main focus is “how to solve”.

What is composition in Javascript?

Function composition is an approach where the result of one function is passed on to the next function, which is passed to another until the final function is executed for the final result. Function compositions can be composed of any number of functions.


1 Answers

join is using the instance of Monad for (->) a, as defined in Control.Monad.Instances. The instance is similar to Reader, but without an explicit wrapper. It is defined like this:

instance Monad ((->) a) where
  -- return :: b -> (a -> b)
  return = const
  -- (>>=) :: (a -> b) -> (b -> a -> c) -> (a -> c)
  f >>= g = \x -> g (f x) x

If you now reduce join using this instance:

join
(>>= id)
flip (\f g x -> g (f x) x) (\a -> a)
(\f x -> (\a -> a) (f x) x)
(\f x -> f x x)

As you can see, the instance for (->) a makes join to a function that applies an argument twice. Because of this, join (*) is simply \x -> x * x.

like image 58
fuz Avatar answered Sep 30 '22 02:09

fuz