I know I can do:
fn1 :: B -> C
fn2 :: (A -> B) -> (A -> C)
fn2 callback = callback >>> fn2
But how do I compose (>>>
) a function with two arguments?:
fn3 :: (Z -> A -> B) -> (Z -> A -> C)
fn3 callback = callback (\z a -> fn1 z a # fn2) ✅
fn3' :: (Z -> A -> B) -> (Z -> A -> C)
fn3' callback = callback (???) fn2 -- >>> won't work 💥
What should ???
operator be to return be exactly like >>>
but taking the additional parameter needed for fn1
before running fn2
as >>>
won't work?
I'm trying to FFI this function more elegantly
const functions = require("firebase-functions");
exports.onRequestImp = function (handler) {
return functions.https.onRequest((request, response) => {
handler(request)(response)();
});
}
module Firebase.Functions.HTTP (onRequest) where
import Prelude
import Control.Promise (Promise, fromAff)
import Effect (Effect)
import Effect.Aff (Aff)
import Node.Express.Types (Request, Response)
foreign import onRequestImp :: (Request -> Response -> Effect (Promise (Unit))) -> Effect Unit
onRequest :: (Request -> Response -> Aff (Unit)) -> Effect Unit
onRequest handler = do
onRequestImp
( \req res -> do
handler req res # fromAff
)
First of all, your type signatures seem way off. In your first code block, with the definition of fn3
that you provide, it should look like this:
fn3 :: A -> C
fn3 = fn1 >>> fn2
Similarly, if I understood the spirit of the question right, in the second code block, the composed type should be:
fn3 :: A -> B -> D
That is, you take the output of fn1
and give it as input to fn2
.
With that out of the way, let's talk about composition. The answer is: yes and no.
No, there is no such composition operator/function in the standard library, because it's usually not useful. Composing functions like this heavily obscures what's going on and makes your program that much harder to maintain.
But also, yes, there is such composition operator/function defined in a library that is specifically aimed at writing point-free programs - compose2
and its friend compose2Flipped
, aliased in operator form as <..
and ..>
respectively:
import PointFree ((..>))
fn1 :: A -> B -> C
fn2 :: C -> D
fn4 :: A -> B -> D
fn4 = fn1 ..> fn2
Having said that, I strongly advise against using such composition. Point-free notation is neat and cool, but in practice it just makes your program incomprehensible. Much better just to write exactly what you mean:
fn4 :: A -> B -> D
fn4 a b = fn2 (fn1 a b)
P.S. Here's a neat trick: how do you think I found that library? It's not like I have all the libraries and all their types and functions memorized, right?
I used the Pursuit search. I knew the type signature of the function you seek would be (a -> b -> c) -> (c -> d) -> (a -> b -> d)
and I just plugged that into search, and voila!
Here, try it yourself: https://pursuit.purescript.org/search?q=(a+-%3E+b+-%3E+c)+-%3E+(c+-%3E+d)+-%3E+(a+-%3E+b+-%3E+d)