Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 21 03:49
    sporto starred fsprojects/FSharpPlus
  • Oct 20 18:25
    wallymathieu commented #191
  • Oct 20 18:13
    cmeeren commented #191
  • Oct 20 17:38
    wallymathieu commented #191
  • Oct 20 17:34
    wallymathieu commented #470
  • Oct 20 15:14
    modotte starred fsprojects/FSharpPlus
  • Oct 20 12:57
    lumikalt starred fsprojects/FSharpPlus
  • Oct 20 04:59
    natalie-perret-1986 commented #470
  • Oct 20 04:58
    natalie-perret-1986 commented #470
  • Oct 20 04:56
    natalie-perret-1986 commented #470
  • Oct 20 04:54
    natalie-perret-1986 commented #470
  • Oct 20 04:29
    natalie-perret-1986 commented #470
  • Oct 20 03:57
    natalie-perret-1986 commented #470
  • Oct 20 03:38
    natalie-perret-1986 commented #470
  • Oct 19 22:01
    gusty commented #470
  • Oct 19 21:43
    adz commented #470
  • Oct 19 20:23
    gusty commented #470
  • Oct 19 11:23
    natalie-perret-1986 opened #470
  • Oct 13 03:25
    zeshhaan starred fsprojects/FSharpPlus
  • Oct 12 15:25
    Choc13 closed #468
amieres
@amieres
It should be DimensionM<seq<(Element * Element)[]>>
in that example there is no compiler error. The message is a runtime exception
the compiler simply takes my word and compiles as if it were a string
Gustavo Leon
@gusty
Yes, I managed to reproduce it. That's weird. Maybe there's something wrong in F#+ or the F# compiler.
amieres
@amieres
I suspect is a defect in the inference engine
Gustavo Leon
@gusty
@amieres One thing I do frequently to avoid too generic code (with the associated type inerence problems it brings) is to add partial type annotations like ReaderT<_,_> but also using less generic functions.
with less generic functions I mean for instace using Seq.traverse which is generic instead of traverse which is "bi-generic".
actually your CE code will compile fine if you use Seq.sequence instead of sequence
    let zzz =  monad {
                    let! elements = elementsD
                    let! pairs    = elements
                                    |> Seq.map (fun el ->
                                        parentsE |> runOne el : DimensionM<_>
                                    )
                                    |> Seq.sequence
                    printfn "%A" pairs 
                } |> runDimPeriod
Gustavo Leon
@gusty
or you can use Seq.traverse and save a step, it will also work.
amieres
@amieres
it does work but only because printfn "%A" lets it assume pairs to be of type obj
if instead something more specific is used like: pairs |> Seq.iter (printfn "%A")
the compiler fails
Type constraint mismatch when applying the default type 'obj' for a type inference variable. No overloads match for method '<*>'
Sandeep Chandra
@sandeepc24

I am trying to use monad Reader to implement DI as talked about https://youtu.be/pxJCHJgG8ws?t=3415

Following is my sample app based on the talk, but I am getting error for function addShoppingList, can somebody please help me?

// Learn more about F# at http://fsharp.org

open System
open FSharpPlus
open FSharpPlus.Data

type IUserRepository =
    abstract GetUser : email : string -> string

type IShoppingListRepository =
    abstract Add : shoppingList : string list -> string list

let getUser email =
    Reader(fun (env : IUserRepository) -> env.GetUser email)

let addShoppingList shoppingList =
    Reader(fun (env : IShoppingListRepository) -> env.Add shoppingList)

let addShoppingList email = monad {
    let! user = getUser email
    let shoppingList = ["s"]
    return! addShoppingList shoppingList
}

let userRepo =
    {
        new IUserRepository with
            member this.GetUser email =
                "Sandeep"
    }

let shoppingListRepo =
    {
        new IShoppingListRepository with
            member this.Add shoppingList =
                shoppingList
    }


[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"
    0 // return an integer exit code
Oskar Gewalli
@wallymathieu
Yes, I'm also interesting in seeing that example compile :)
amieres
@amieres
@sandeepc24 The issue is that you can use only one monad type in a CE.
Your 2 monads are of different types: Reader<IUserRepository, _>and Reader<IShoppingListRepository, _>
you can make them both generic by declaring them like this:
let getUser email =
    Reader(fun (env : #IUserRepository) -> env.GetUser email)

let addShoppingList shoppingList =
    Reader(fun (env : #IShoppingListRepository) -> env.Add shoppingList)
that way you can combine them. Then your env object needs to implement both interfaces:
amieres
@amieres
type Env() =
    interface IUserRepository with
        member this.GetUser email =
                "Sandeep"    
    interface IShoppingListRepository with
            member this.Add shoppingList =
                shoppingList
sandeep-eroad
@sandeep-eroad
that works, thanks. Could someone show how to use it in Asp.NET Giraffe app?
sandeep-eroad
@sandeep-eroad
where there are async functions
amieres
@amieres
@sandeep-eroad when you need to combine a Reader with another monad(like Async) you use a monad transformer like ReaderT:
type IUserRepository =
    abstract GetUser : email : string -> Async<string>

type IShoppingListRepository =
    abstract Add : shoppingList : string list -> string list

let getUser email =
    ReaderT(fun (env : #IUserRepository) -> env.GetUser email )

let addShoppingList shoppingList =
    ReaderT(fun (env : #IShoppingListRepository) -> async { return env.Add shoppingList })

let addShoppingListM email = monad {
    let! user = getUser email
    let shoppingList = ["s"]
    return! addShoppingList shoppingList
}

type Env() =
    interface IUserRepository with
        member this.GetUser email = 
            async { return "Sandeep"}
    interface IShoppingListRepository with
            member this.Add shoppingList =
                shoppingList


ReaderT.run (addShoppingListM "a@a")  (Env()) 
|> fun listA -> async {
    let! list = listA
    printfn "%A" list
} |> Async.Start
sandeep-eroad
@sandeep-eroad
thanks. So, inside of an async function would I call it as shown below?
let someControllerFunc task ctx = async {
    let! result = 
        ReaderT.run (addShoppingListM "a@a") (Env())
        |> fun listA -> async {
            let! list = listA
        }
    return result
}
is there a way to not have ReaderT.run in code?
amieres
@amieres
almost:
let someControllerFunc task ctx = async {
    let! result = 
        ReaderT.run (addShoppingListM "a@a") (Env())
    return result
}
sandeep-eroad
@sandeep-eroad
thanks
amieres
@amieres
usually you want to delay using Reader.run or ReaderT.run to the last possible place in code
but sometimes is not possible
sandeep-eroad
@sandeep-eroad
is there a CE that can be used to write the above code as
let someControllerFunc task ctx = asyncReader {
    let! result =  addShoppingListM "a@a" (Env())
    return result
}
amieres
@amieres
that is what monad { ... } does
sandeep-eroad
@sandeep-eroad
so could I write this as
let someControllerFunc task ctx = monad { let! result = addShoppingListM "a@a" (Env()) return result }
amieres
@amieres
yes
sandeep-eroad
@sandeep-eroad
thanks, I'll try that
amieres
@amieres
note that in this case the CE is not actually doing anything so its equivalent to writing:
let someControllerFunc task ctx = 
      addShoppingListM "a@a" (Env())
but in both cases the return type is ReaderT<Async<_>>
which I do not think is what you want
you probably want it to be simply Async<_>
and for that you need to invoke ReaderT.run
sandeep-eroad
@sandeep-eroad
yes that is what I see
amieres
@amieres
sorry, actually addShoppingListM "a@a" (Env()) is not correct
because you need to pass (Env()) to ReaderT.run
sandeep-eroad
@sandeep-eroad
looks like there is no way to avoid ReaderT.run
amieres
@amieres
let someControllerFunc task ctx : Async<_> = 
      ReaderT.run (addShoppingListM "a@a") (Env())
it is the only way of getting out of the ReaderT monad
sandeep-eroad
@sandeep-eroad
yes
amieres
@amieres
is the exit point