hemanth / functional-programming-jargon

Jargon from the functional programming world in simple terms!
http://git.io/fp-jargons
MIT License
18.59k stars 1.02k forks source link

"lift" is wrong, confusing #70

Closed tabatkins closed 7 years ago

tabatkins commented 8 years ago

The definition of Lift is pretty incorrect. It states

Lift is like map except it can be applied to multiple functors.

but that has nothing to do with lift, that's a property of the functor being applicative. Given an applicative functor, you can apply a function over multiple functor arguments without lift: arg1.of(f).ap(arg1).ap(arg2). (It's definitely not pretty, which is one reason why lifting is so much better, but still.)

The definition is further wrong because it talks about the map-equivalent version of lift, which definitely doesn't have the property being discussed; it only makes the function handle plain functors, not applicative functors. You need the ap-equivalent version (in Haskell, liftA).

lift is just the name given to map/ap/chain when the arguments are reversed (function first, then data) and partially applied.

Here's a suggested rewrite:


"Lift" has a few meanings. Sometimes people will talking about "lifting a value" into a functor; this refers to calling the of function on the value.

When "lift" is referred to as a function, though, it's just a variation of map, ap, or chain that takes the function argument first, and returns a new function that takes the functor value and maps/aps/chains on it. That is, given the map-equivalent version of lift, arg.map(f) is identical to lift(f)(arg). Lifting the function, rather than using map directly, makes it easier to pass the function around and apply it to other values, as it lets you use normal function-call syntax, passing arguments, rather than having to specially use the map method.

This is more obvious when you're using an applicative functor, which allows a function to be called with multiple functor arguments. Using the ap function, you'd have to write [].of(f).ap(arg1).ap(arg2), while lifting lets you just write liftA(f)(arg1, arg2). (You do need to specify which version of lift you're using; traditionally this is done with lift for plain functors, liftA for applicative functors, and liftM for monadic functors.

jethrolarson commented 8 years ago

Thanks for explaining. I can definitely use that to refine the definition.

On Mon, Jul 25, 2016, 11:42 AM Tab Atkins Jr. notifications@github.com wrote:

The definition of Lift is pretty incorrect. It states

Lift is like map except it can be applied to multiple functors.

but that has nothing to do with lift, that's a property of the functor being applicative. Given an applicative functor, you can apply a function over multiple functor arguments without lift: arg1.of(f).ap(arg1).ap(arg2). (It's definitely not pretty, which is one reason why lifting is so much better, but still.)

The definition is further wrong because it talks about the map-equivalent version of lift, which definitely doesn't have the property being discussed; it only makes the function handle plain functors, not applicative functors. You need the ap-equivalent version (in Haskell, liftA).

lift is just the name given to map/ap/chain when the arguments are reversed (function first, then data) and partially applied.

Here's a suggested rewrite:

"Lift" has a few meanings. Sometimes people will talking about "lifting a value" into a functor; this refers to calling the of function on the value.

When "lift" is referred to as a function, though, it's just a variation of map, ap, or chain that takes the function argument first, and returns a new function that takes the functor value and maps/aps/chains on it. That is, given the map-equivalent version of lift, arg.map(f) is identical to lift(f)(arg). Lifting the function, rather than using map directly, makes it easier to pass the function around and apply it to other values, as it lets you use normal function-call syntax, passing arguments, rather than having to specially use the map method.

This is more obvious when you're using an applicative functor, which allows a function to be called with multiple functor arguments. Using the ap function, you'd have to write [].of(f).ap(arg1).ap(arg2), while lifting lets you just write liftA(f)(arg1, arg2). (You do need to specify which version of lift you're using; traditionally this is done with lift for plain functors, liftA for applicative functors, and liftM for monadic functors.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/hemanth/functional-programming-jargon/issues/70, or mute the thread https://github.com/notifications/unsubscribe-auth/AAB-4MXlUpuCVDuMJlkmnSMcJcsOjeIgks5qZQN3gaJpZM4JUa9t .

hemanth commented 8 years ago

Awesome, a PR would be really useful! @tabatkins

Thank you @jethrolarson! 👍

jethrolarson commented 7 years ago

Been almost a year, so I think we can close.