Skip to content
This repository has been archived by the owner on Feb 22, 2022. It is now read-only.

[Suggestion] Combinator operators for partial application of functions wrapped in Freya computations #189

Open
Vidarls opened this issue Mar 22, 2016 · 5 comments

Comments

@Vidarls
Copy link
Contributor

Vidarls commented Mar 22, 2016

As I previously mentioned in #182 I've had some issues getting to grips being inside / outside Freya computations. Particularly with regards to passing around partially applied functions that requires arguments from inside a Freya computation, (and thus themselves get wrapped in a Freya computation after..)

I ended up creating the some custom operators (again).

(Btw, I really wish F# would support named operators, rather than just symbolic ones, would help readability a lot..)

I do have a lot of holes in my functional vocabulary, so I have no idea what to actually call these but here they are:

let (<!^>) f v = 
    freya {
        let! f = f 
        return f v
    } 

let (<^!>) f v = 
    freya {
        let! v = v
        return! f v
    }

The first operator will take a function wrapped in a Freya computation, "dereference" it(?) and apply the given argument, returning the result wrapped in a Freya computation.

Example:

open Freya.Core.Operators

let myFunction with' some args = 
    (...)

let myValueInAFreya = 
    freya {
        return "some stuff"
    }

let myValueNotInAFreya = 
    "some stuff"
let myPartiallyAppliedOne = myFunction <!> myValueInAFreya
// Above is now Freya<'a->'b->'c>
// I want to add another arg partially applied

let myPartiallyAppliedTwo = myPartiallyAppliedOne <!^> myValueNotInAFreya
// Above is now Freya<'a->'b>

It is possible I have misunderstood something, but adding the new operator helped me quite a bit..

The scenario for the other operator is a bit more weird. I ended up creating it because using the standard <!> map(?) operator ended up giving med nested Freyas (Freya<Freya<'t>>) which I was not what I was looking for.

Example:

let myFunctionNotInAFreya some arg = 
    (...)

let myFunctionReturningAFreyaWrappedFun () = 
    freya {
        return (fun x -> x.ToString())
    }

//this gives me nested Freyas:

let normalMap = myFunctionNotInAFreya <!> (myFunctionReturningAFreyaWrappedFun ())
// above gives `Freya<Freya<'a->'b>>`

// using my operator:
let asExpected = myFunctionNotInAFreya <^!> (myFunctionReturningAFreyaWrappedFun ())
//above gives `Freya<'a->'b>`as expected.

This may or may not be something to include as part of the core operators..

@Vidarls
Copy link
Contributor Author

Vidarls commented Apr 4, 2016

ping @kolektiv This is the one I would like some feedback on before doing a PR on operators.

@kolektiv
Copy link
Member

kolektiv commented Apr 4, 2016

I don't see why not :) There are ways of writing them using the more "common" operators, but they're less concise, and we wouldn't be mandating these. I think this would be fine, but I'd probably add them to an extra module under Freya.Operators - something like Freya.Operators.Extended to signify that these are probably a bit more special purpose. But I'd be happy to take that I think!

@Vidarls
Copy link
Contributor Author

Vidarls commented Apr 5, 2016

Ok, I'll give it a go.

Just for my education: would you mind giving an example of how to to this with the "common" operators. And perhaps also give some suggestion on what to name my shortcuts?

@kolektiv
Copy link
Member

kolektiv commented Apr 5, 2016

Sure, let me put something together :) I'll have a think on the naming!

@kolektiv
Copy link
Member

kolektiv commented Apr 5, 2016

Not sure how clear this is, but maybe useful - and I think doing the same thing! The first one is slightly awkward, although could be slightly tidied up by defining a function let apply a b = b a and then replacing the function definition with simply apply x as shown:

// First

let (<!^>) f v =
    freya {
        let! f = f
        return f v }

let double =
    freya {
        return (fun x -> x * 2) }

let doubled x =
    double <!^> x

// or

let doubled' x =
    (fun f -> f x) <!> double

// or

let apply a b =
    b a

let doubled'' x =
    apply x <!> double

// Second

let (<^!>) f v =
    freya {
        let! v = v
        return! f v }

let triple x =
    freya {
        return x * 3 }

let tripled x =
    triple <^!> Freya.init x

// or

let tripled' x =
    Freya.init x >>= triple // or: triple =<< Freya.init x

Hopefully that's useful?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants