I wrote implementations of applyFirst and applyLast as I thought they should work and then merged them according to applyFirst(applyLast, map) and I really got the splat function as described in the next code block. My problem is I still don't get why applyFirst(applyLast, map) works. I'm feeling that all this return function(param1, param2) notation obscures actual flow.
Is there a notation for this that could make me understand it intuitively?
I'm not aware of specific notation, but let's first see the difference between map and splat:
map is a function that takes a list and a function and returns a list
map :: (function, list) -> list
splat is a function that takes a function and returns a function that takes a list and returns a list
splat :: (function)->((list)->list)
That is sort of effectively the reverse order of parameters for map. What applyFirst does is, it takes a function and a parameter and returns a function that takes more params and prepends the given one. applyLast is similar, but appends the given one. Let's walk through the application of applyFirst(applyLast, map)(fn)(list)
applyFirst(applyLast, map)(fn)(list)
applyLast(map, fn)(list) -- here applyFirst has supplied the map param to applyLast and fn is the given param
map(list, fn) -- and here applyLast as supplied the fn param to map, putting list first
If you supply more parameters, you'd get:
applyFirst(applyLast, map)(a, b)(c, d)
...
map(c, d, a, b)
Which wouldn't work with map per se, but shows how the applyFirst(applyLast, map) construction works.
After your excelent suggestions for names
(makeMapper and makeGetter, they make everything easier, thank you),
I'll try answering this, with a F#-like syntax using redundant parentheses
around arguments to make them more explicit
to those who don't know F#
Let's suppose map is defined as:
> let map (aList) (aFunction) = ...something here...
Read the above as: makeMapper is a function just like applyLast,
but the first argument (to applyLast) is already provided, being "map".
The functionality of applyFirst is implicit when the
remanining parameters are missing, so we only need applyLast.
So makeMapper is called as
> let mapperWithAGetter = makeMapper (aGetter)
This completes the call to applyLast,
so now we have a (fun (x) -> map (x) (aGetter))
Now we only need to bind x. The result is called like this
> mapperWithAGetter (aList)
IMO, all of this could've been written as:
> let makeMapper (aGetter) = fun (aList) -> map (aList) (aGetter)
Or:
> let makeMapper (aGetter) (aList) = map (aList) (aGetter)
Read both as: makeMapper takes aGetter and returns
a function which takes aList
Notice that everything would be much easiear if map took aFunction
as its first parameter:
> let map (aFunction) (aList) = ...
> let makeMapper = map // duh
Remember that partial application is implicit!
It would also be easier if applyLast had better syntax,
using _ for the missing parameter (the first), as in this
Scala-like snippet:
I wrote implementations of applyFirst and applyLast as I thought they should work and then merged them according to applyFirst(applyLast, map) and I really got the splat function as described in the next code block. My problem is I still don't get why applyFirst(applyLast, map) works. I'm feeling that all this return function(param1, param2) notation obscures actual flow.
Is there a notation for this that could make me understand it intuitively?