I am building an authenticated web API using Suave, and I often stumble on the problem of aggregating infos throughout different functions
pathScan Navigation.playersAvailables GetGame >>= getInSession >>= (fun (gameId,playerInSession) -> //access to both gameId and player in session)
signatures :
getGame : HttpContext -> Async<HttpContext option>
getInSession : HttpContext -> Async<HttpContext option>
getGame take id from httpContext.request.querystring getInSession
take sessionId from httpContext.cookie
The only thing I found in order to do that was to store infos in the userDataDictionnary :
Writers.setUserData "player" { playerId= playersId; socialId=socialId; username = username}
And to retrieve it in the other function but it looks pretty nasty to me :
let player = x.userState.["player"] :?> PlayerSession
//do some other stuff now that we have the current player
Is there another way of doing that? I would like to have pure functions like
getGameId and get Session, etc.. and to be able to compose them as I wish to process my different routes :
pathScan Navigation.playersAvailables GetGame >>= getInSession >>= (fun (gameId,playerInSession) -> //access to both gameId and player in session)
pathScan Navigation.otherRoute GetGame >>= (fun (gameId) -> //process gameId)
pathScan Navigation.otherRoute2 getInSession >>= (fun (sessionId) -> //process sessionId to do some other stuff)
I am afraid that what I need is a day talk with some real functionnal programmer..
setUserData is a pure function - src.
Not sure if this is still current but it says pathScan and >>= cannot be nicely chained. However I think the Writers.setUserData you are using may be able to accomplish it.
Accessing an object bag to pull things out isn't lovely.
how about:
let (|ParseInt|_|) =
function
| "" | null -> None
| x ->
match Int32.TryParse x with
| true, i -> Some i
| _ -> None
let (|HasParam|_|) name (ctx:HttpContext) =
ctx.request.queryParam name
|> function
|Choice1Of2 value ->
Some value
| _ -> None
let playersAvailablePart:WebPart =
function
//access to both gameId and player in session
|HasParam "inSession" playerInSession & HasParam "gameId" gameId as ctx ->
// do your processing here, sample return:
OK "we had all the required important parts" ctx
// or an example of something more strongly typed
| HasParam "inSession" (ParseInt playerInSession) & HasParam "gameId" (ParseInt gameId) as ctx ->
// do your processing here, sample return:
OK "we had all the required important parts" ctx
| ctx -> never ctx
This doesn't exactly work if the values aren't in the queryParameters, but you can adapt it to where they are
Related
I have a DU (don't worry about the specific types, but 2 normal options, or some errors)
type Content =
| Episode of EpisodeJSON.Root
| Program of string
| Errors of List<exn>
I have 2 functions (again the specifics don't matter, just the types):
let getEpisode : _ -> _ -> Async<Content> = ...
let getProgram : _ -> _ -> Async<Content> = ...
I want to write
let getContent : _ -> _ -> Async<Content> =
fun (contentBAPIClient: ContentBAPI.Client) id -> ...
such that, it tries to get the data from getEpisode, if there's an error, it tries to get it from getProgram, and if there is an error again, it returns both errors as the Error DU.
so, this works
let getContent : _ -> _ -> Async<Content> =
fun (contentBAPIClient: ContentBAPI.Client) id ->
async {
let! episodeMaybe = getEpisode contentBAPIClient id
let! programMaybe = getProgram contentBAPIClient id
return
match episodeMaybe with
| Errors xs ->
match programMaybe with
| Errors ys ->
Errors (List.append xs ys)
| program ->
program
| episode ->
episode
}
but I notice that getprogram is being executed even when the data is found via getepisode.
How do i structure this simple function to try getEpisode first, then only try getProgram if episode 'fails'
this works, still feels a bit clunky
let getContent : _ -> _ -> Async<Content> =
fun (contentBAPIClient: ContentBAPI.Client) id ->
async {
let! episodeMaybe = getEpisode contentBAPIClient id
match episodeMaybe with
| Errors xs ->
let! programMaybe = getProgram contentBAPIClient id
match programMaybe with
| Errors ys ->
return Errors (List.append xs ys)
| program ->
return program
| episode ->
return episode
}
This will get a lot easier if you use some library that lets you work with values representing asynchronous computations that may fail, i.e. type Async<Result<'TOk, 'TErrror>>.
A good choice would be something like FsToolkit.ErrorHandling. This defines the asyncResult computation expression as well as a number of primitives that you may find useful.
To get this to compile, I started with this:
#r "nuget: FsToolkit.ErrorHandling"
open FsToolkit.ErrorHandling
type Client = class end
let getEpisode contentBAPIClient id =
async { return Error ["no episode"] }
let getProgram contentBAPIClient id =
async { return Ok "fine" }
Now, to do what (I think) you are doing, you can use:
let getContent (contentBAPIClient: Client) id =
getEpisode contentBAPIClient id
|> AsyncResult.orElseWith (fun e1 ->
getProgram contentBAPIClient id
|> AsyncResult.mapError (fun e2 -> e1 # e2) )
Here, we try to return the episode, but if there is not one, we try to get program (using orElseWith). The only tricky thing is that we need to pass the errors from the first call, which are then appended to (potential) errors of the second call using mapError.
Note that you can also write:
let getContent (contentBAPIClient: Client) id =
asyncResult {
let! ep = getEpisode contentBAPIClient id
and! prog = getProgram contentBAPIClient id
return ep, prog }
This succeeds only if both calls succeed, so it can be quite useful in many scenarios, but does not exactly do the thing that you are trying to do.
Previously had a very compact and comprehensive answer for my question.
I had it working for my custom type but now due to some reason I had to change it to string type which is now causing type mismatch errors.
module AsyncResult =
let bind (binder : 'a -> Async<Result<'b, 'c>>) (asyncFun : Async<Result<'a, 'c>>) : Async<Result<'b, 'c>> =
async {
let! result = asyncFun
match result with
| Error e -> return Error e
| Ok x -> return! binder x
}
let compose (f : 'a -> Async<Result<'b, 'e>>) (g : 'b -> Async<Result<'c, 'e>>) = fun x -> bind g (f x)
let (>>=) a f = bind f a
let (>=>) f g = compose f g
Railway Oriented functions
let create (json: string) : Async<Result<string, Error>> =
let url = "http://api.example.com"
let request = WebRequest.CreateHttp(Uri url)
request.Method <- "GET"
async {
try
// http call
return Ok "result"
with :? WebException as e ->
return Error {Code = 500; Message = "Internal Server Error"}
}
test
type mismatch error for the AsyncResult.bind line
let chain = create
>> AsyncResult.bind (fun (result: string) -> (async {return Ok "more results"}))
match chain "initial data" |> Async.RunSynchronously with
| Ok data -> Assert.IsTrue(true)
| Error error -> Assert.IsTrue(false)
Error details:
EntityTests.fs(101, 25): [FS0001] Type mismatch. Expecting a '(string -> string -> Async<Result<string,Error>>) -> 'a' but given a 'Async<Result<'b,'c>> -> Async<Result<'d,'c>>' The type 'string -> string -> Async<Result<string,Error>>' does not match the type 'Async<Result<'a,'b>>'.
EntityTests.fs(101, 25): [FS0001] Type mismatch. Expecting a '(string -> string -> Async<Result<string,Error>>) -> 'a' but given a 'Async<Result<string,'b>> -> Async<Result<string,'b>>' The type 'string -> string -> Async<Result<string,Error>>' does not match the type 'Async<Result<string,'a>>'.
Edit
Curried or partial application
In context of above example, is it the problem with curried functions? for instance if create function has this signature.
let create (token: string) (json: string) : Async<Result<string, Error>> =
and then later build chain with curried function
let chain = create "token" >> AsyncResult.bind (fun (result: string) -> (async {return Ok "more results"}))
Edit 2
Is there a problem with following case?
signature
let create (token: Token) (entityName: string) (entityType: string) (publicationId: string) : Async<Result<string, Error>> =
test
let chain = create token >> AsyncResult.bind ( fun (result: string) -> async {return Ok "more results"} )
match chain "test" "article" "pubid" |> Async.RunSynchronously with
Update: At the front of the answer, even, since your edit 2 changes everything.
In your edit 2, you have finally revealed your actual code, and your problem is very simple: you're misunderstanding how the types work in a curried F# function.
When your create function looked like let create (json: string) = ..., it was a function of one parameter. It took a string, and returned a result type (in this case, Async<Result<string, Error>>). So the function signature was string -> Async<Result<string, Error>>.
But the create function you've just shown us is a different type entirely. It takes four parameters (one Token and three strings), not one. That means its signature is:
Token -> string -> string -> string -> Async<Result<string, Error>>
Remember how currying works: any function of multiple parameters can be thought of as a series of functions of one parameter, which return the "next" function in that chain. E.g., let add3 a b c = a + b + c is of type int -> int -> int -> int; this means that add3 1 returns a function that's equivalent to let add2 b c = 1 + b + c. And so on.
Now, keeping currying in mind, look at your function type. When you pass a single Token value to it as you do in your example (where it's called as create token, you get a function of type:
string -> string -> string -> Async<Result<string, Error>>
This is a function that takes a string, which returns another function that takes a string, which returns a third function which takes a string and returns an Async<Result<whatever>>. Now compare that to the type of the binder parameter in your bind function:
(binder : 'a -> Async<Result<'b, 'c>>)
Here, 'a is string, so is 'b, and 'c is Error. So when the generic bind function is applied to your specific case, it's looking for a function of type string -> Async<Result<'b, 'c>>. But you're giving it a function of type string -> string -> string -> Async<Result<string, Error>>. Those two function types are not the same!
That's the fundamental cause of your type error. You're trying to apply a function that returns a function that returns function that returns a result of type X to a design pattern (the bind design pattern) that expects a function that returns a result of type X. What you need is the design pattern called apply. I have to leave quite soon so I don't have time to write you an explanation of how to use apply, but fortunately Scott Wlaschin has already written a good one. It covers a lot, not just "apply", but you'll find the details about apply in there as well. And that's the cause of your problem: you used bind when you needed to use apply.
Original answer follows:
I don't yet know for a fact what's causing your problem, but I have a suspicion. But first, I want to comment that the parameter names for your AsyncResult.bind are wrong. Here's what you wrote:
let bind (binder : 'a -> Async<Result<'b, 'c>>)
(asyncFun : Async<Result<'a, 'c>>) : Async<Result<'b, 'c>> =
(I moved the second parameter in line with the first parameter so it wouldn't scroll on Stack Overflow's smallish column size, but that would compile correctly if the types were right: since the two parameters are lined up vertically, F# would know that they are both belonging to the same "parent", in this case a function.)
Look at your second parameter. You've named it asyncFun, but there's no arrow in its type description. That's not a function, it's a value. A function would look like something -> somethingElse. You should name it something like asyncValue, not asyncFun. By naming it asyncFun, you're setting yourself up for confusion later.
Now for the answer to the question you asked. I think your problem is this line, where you've fallen afoul of the F# "offside rule":
let chain = create
>> AsyncResult.bind (fun (result: string) -> (async {return Ok "more results"}))
Note the position of the >> operator, which is to the left of its first operand. Yes, the F# syntax appears to allow that in most situations, but I suspect that if you simply change that function definition to the following, your code will work:
let chain =
create
>> AsyncResult.bind (fun (result: string) -> (async {return Ok "more results"}))
Or, better yet because it's good style to make the |> (and >>) operators line up with their first operand:
let chain =
create
>> AsyncResult.bind (fun (result: string) -> (async {return Ok "more results"}))
If you look carefully at the rules that Scott Wlaschin lays out in https://fsharpforfunandprofit.com/posts/fsharp-syntax/, you'll note that his examples where he shows exceptions to the "offside rule", he writes them like this:
let f g h = g // defines a new line at col 15
>> h // ">>" allowed to be outside the line
Note how the >> character is still to the right of the = in the function definition. I don't know exactly what the F# spec says about the combination of function definitions and the offside rule (Scott Wlaschin is great, but he's not the spec so he could be wrong, and I don't have time to look up the spec right now), but I've seen it do funny things that I didn't quite expect when I wrote functions with part of the function definition on the same line as the function, and the rest on the next line.
E.g., I once wrote something like this, which didn't work:
let f a = if a = 0 then
printfn "Zero"
else
printfn "Non-zero"
But then I changed it to this, which did work:
let f a =
if a = 0 then
printfn "Zero"
else
printfn "Non-zero"
I notice that in Snapshot's answer, he made your chain function be defined on a single line, and that worked for him. So I suspect that that's your problem.
Rule of thumb: If your function has anything after the = on the same line, make the function all on one line. If your function is going to be two lines, put nothing after the =. E.g.:
let f a b = a + b // This is fine
let g c d =
c * d // This is also fine
let h x y = x
+ y // This is asking for trouble
I would suspect that the error stems from a minor change in indentation since adding a single space to an FSharp program changes its meaning, the FSharp compiler than quickly reports phantom errors because it interprets the input differently. I just pasted it in and added bogus classes and removed some spaces and now it is working just fine.
module AsyncResult =
[<StructuralEquality; StructuralComparison>]
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError
let bind (binder : 'a -> Async<Result<'b, 'c>>) (asyncFun : Async<Result<'a, 'c>>) : Async<Result<'b, 'c>> =
async {
let! result = asyncFun
match result with
| Error e -> return Error e
| Ok x -> return! binder x
}
let compose (f : 'a -> Async<Result<'b, 'e>>) (g : 'b -> Async<Result<'c, 'e>>) = fun x -> bind g (f x)
let (>>=) a f = bind f a
let (>=>) f g = compose f g
open AsyncResult
open System.Net
type Assert =
static member IsTrue (conditional:bool) = System.Diagnostics.Debug.Assert(conditional)
type Error = {Code:int; Message:string}
[<EntryPoint>]
let main args =
let create (json: string) : Async<Result<string, Error>> =
let url = "http://api.example.com"
let request = WebRequest.CreateHttp(Uri url)
request.Method <- "GET"
async {
try
// http call
return Ok "result"
with :? WebException as e ->
return Error {Code = 500; Message = "Internal Server Error"}
}
let chain = create >> AsyncResult.bind (fun (result: string) -> (async {return Ok "more results"}))
match chain "initial data" |> Async.RunSynchronously with
| Ok data -> Assert.IsTrue(true)
| Error error -> Assert.IsTrue(false)
0
Currently i'm working in a game and use Event/Observables much, one thing i run into was to eliminate some redundant code, and i didn't found a way to do it. To explain it, let's assume we have following DU and an Observable for this DU.
type Health =
| Healed
| Damaged
| Died
| Revived
let health = Event<Health>()
let pub = health.Publish
I have a lot of this kind of structures. Having all "Health" Messages grouped together is helpfull and needed in some situations, but in some situations i only care for a special Message. Because that is still often needed i use Observable.choose to separate those message. I have then code like this.
let healed = pub |> Observable.choose (function
| Healed -> Some ()
| _ -> None
)
let damaged = pub |> Observable.choose (function
| Damaged -> Some ()
| _ -> None
)
Writing this kind of code is actually pretty repetitive and annoying. I have a lot of those types and messages. So one "rule" of functional programming is "Parametrize all the things". So i wrote a function only to just help me.
let only msg pub = pub |> Observable.choose (function
| x when x = msg -> Some ()
| _ -> None
)
With such a function in place, now the code becomes a lot shorter and less annoying to write.
let healed = pub |> only Healed
let damaged = pub |> only Damaged
let died = pub |> only Died
let revived = pub |> only Revived
EDIT:
The important thing to note. healed, damaged, died, revived are now of type IObservable<unit> not IObservable<Health>. The idea is not just to separate the messages. This can be easily achieved with Observable.filter. The idea is that the the data for each case additional get extracted. For DU case that don't carry any additional data this is easy, as i only have to write Some () in the Observable.choose function.
But this only works, as long the different cases in a DU don't expect additional values. Unlucky i also have a lot of cases that carry additional information. For example instead of Healed or Damaged i have HealedBy of int. So a message also contains additional how much something got healed. What i'm doing is something like this, in this case.
let healedBy = pub |> Observable.choose (function
| HealedBy x -> Some x
| _ -> None
)
But what i really want is to write it something like this
let healedBy = pub |> onlyWith HealeadBy
What i'm expecting is to get an Observable<int>. And i didn't found any way how to do it. I cannot write a function like only above. because when i try to evaluate msg inside a Pattern Matching then it is just seen as a variable to Pattern Match all cases. I cannot say something like: "Match on the case inside the variable."
I can check if a variable is of some specific case. I can do if x = HealedBy then but after that, i cannot extract any kind of data from x. What i'm really need is something like an "unsecure" extracting like option for example provide it with optional.Value. Does there exists any way to implement such a "onlyWith" function to remove the boilerplate?
EDIT:
The idea is not just separating the different messages. This can be achieved through Observable.filter. Here healedBy is of type IObservable<int> NOT IObservable<Health> anymore. The big idea is to separate the messages AND extract the data it carries along AND doing it without much boilerplate. I already can separate and extract it in one go with Observable.choose currently. As long as a case don't have any additional data i can use the only function to get rid of the boilerplate.
But as soon a case has additional data i'm back at writing the repetitive Observable.Choose function and do all the Pattern Matching again. The thing is currently i have code like this.
let observ = pub |> Observable.choose (function
| X (a) -> Some a
| _ -> None
)
And i have this kind of stuff for a lot of messages and different types. But the only thing that changes is the "X" in it. So i obviously want to Parameterize "X" so i don't have to write the whole construct again and again. At best it just should be
let observ = anyObservable |> onlyWith CaseIWantToSeparate
But the new Observable is of the type of the specific case i separated. Not the type of the DU itself.
The behaviour it appears you are looking for doesn't exist, it works fine in your first example because you can always consistently return a unit option.
let only msg pub =
pub |> Observable.choose (function
| x when x = msg -> Some ()
| _ -> None)
Notice that this has type: 'a -> IObservable<'a> -> IObservable<unit>
Now, let's imagine for the sake of creating a clear example that I define some new DU that can contain several types:
type Example =
|String of string
|Int of int
|Float of float
Imagine, as a thought exercise, I now try to define some general function that does the same as the above. What might its type signature be?
Example -> IObservable<Example> -> IObservable<???>
??? can't be any of the concrete types above because the types are all different, nor can it be a generic type for the same reason.
Since it's impossible to come up with a sensible type signature for this function, that's a pretty strong implication that this isn't the way to do it.
The core of the problem you are experiencing is that you can't decide on a return type at runtime, returning a data type that can be of several different possible but defined cases is precisely the problem discriminated unions help you solve.
As such, your only option is to explicitly handle each case, you already know or have seen several options for how to do this. Personally, I don't see anything too horrible about defining some helper functions to use:
let tryGetHealedValue = function
|HealedBy hp -> Some hp
|None -> None
let tryGetDamagedValue = function
|DamagedBy dmg -> Some dmg
|None -> None
The usual route in these situations is to define predicates for cases, and then use them for filtering:
type Health = | Healed | Damaged | Died | Revived
let isHealed = function | Healed -> true | _ -> false
let isDamaged = function | Damaged -> true | _ -> false
let isDied = function | Died -> true | _ -> false
let isRevived = function | Revived -> true | _ -> false
let onlyHealed = pub |> Observable.filter isHealed
UPDATE
Based on your comment: if you want to not only filter messages, but also unwrap their data, you can define similar option-typed functions and use them with Observable.choose:
type Health = | HealedBy of int | DamagedBy of int | Died | Revived
let getHealed = function | HealedBy x -> Some x | _ -> None
let getDamaged = function | DamagedBy x -> Some x | _ -> None
let getDied = function | Died -> Some() | _ -> None
let getRevived = function | Revived -> Some() | _ -> None
let onlyHealed = pub |> Observable.choose getHealed // : Observable<int>
let onlyDamaged = pub |> Observable.choose getDamaged // : Observable<int>
let onlyDied = pub |> Observable.choose getDied // : Observable<unit>
You can use reflection to do this I think. This might be pretty slow:
open Microsoft.FSharp.Reflection
type Health =
| Healed of int
| Damaged of int
| Died
| Revived
let GetUnionCaseInfo (x:'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, [||] -> (case.Name, null )
| case, value -> (case.Name, value.[0] )
let health = Event<Health>()
let pub = health.Publish
let only msg pub = pub |> Observable.choose (function
| x when x = msg -> Some(snd (GetUnionCaseInfo(x)))
| x when fst (GetUnionCaseInfo(x)) = fst (GetUnionCaseInfo(msg))
-> Some(snd (GetUnionCaseInfo(x)))
| _ -> None
)
let healed = pub |> only (Healed 0)
let damaged = pub |> only (Damaged 0)
let died = pub |> only Died
let revived = pub |> only Revived
[<EntryPoint>]
let main argv =
let healing = Healed 50
let damage = Damaged 100
let die = Died
let revive = Revived
healed.Add (fun i ->
printfn "We healed for %A." i)
damaged.Add (fun i ->
printfn "We took %A damage." i)
died.Add (fun i ->
printfn "We died.")
revived.Add (fun i ->
printfn "We revived.")
health.Trigger(damage)
//We took 100 damage.
health.Trigger(die)
//We died.
health.Trigger(healing)
//We healed for 50.
health.Trigger(revive)
//We revived.
0 // return an integer exit code
It doesn't feel like you can get your onlyWith function without making some significant changes elsewhere. You can't really generalize the function you pass in for the HealedBy case while staying within the type system (I suppose you could cheat with reflection).
One thing that seems like a good idea would be to introduce a wrapper for the Healed type instead of having a HealedBy type:
type QuantifiedHealth<'a> = { health: Health; amount: 'a }
and then you can have an onlyWith function like this:
let onlyWith msg pub =
pub |> Observable.choose (function
| { health = health; amount = amount } when health = msg -> Some amount
| _ -> None)
I guess you can even go one step further while you're at it, and parameterize your type by both the label and the amount types to make it truly generic:
type Quantified<'label,'amount> = { label: 'label; amount: 'amount }
Edit: To reitarate, you keep this DU:
type Health =
| Healed
| Damaged
| Died
| Revived
Then you make your health event - still a single one - use the Quantified type:
let health = Event<Quantified<Health, int>>()
let pub = health.Publish
You can trigger the event with messages like { label = Healed; amount = 10 } or { label = Died; amount = 0 }. And you can use the only and onlyWith functions to filter and project the event stream to IObservable<unit> and IObservable<int> respectively, without introducing any boilerplate filtering functions.
let healed : IObservable<int> = pub |> onlyWith Healed
let damaged : IObservable<int> = pub |> onlyWith Damaged
let died : IObservable<unit> = pub |> only Died
let revived : IObservable<unit> = pub |> only Revived
The label alone is enough to differentiate between records representing "Healed" and "Died" cases, you no longer need to walk around the payload you would have in your old "HealedBy" case. Also, if you now add a Mana or Stamina DU, you can reuse the same generic functions with Quantified<Mana, float> type etc.
Does this make sense to you?
Arguably it's slightly contrived compared to a simple DU with "HealedBy" and "DamagedBy", but it does optimize the use case that you care for.
I would like to do some unit tests on a function that accepts a DU and returns another :
type Commands =
| Schedule of string
| Abandon of string
type Events =
| Scheduled of string
| Abandonned of string
the function is the following :
let exec state = function
| Schedule (cmd) -> Choice1Of2( Scheduled("yes"))
| Abandon(cmd) -> Choice1Of2( Abandonned ("no"))
My tests are as follows :
let result:Choice<Events,string> = exec "initial state" <| Schedule("myCommand");;
result has the following type Choice<Events,string>, I would have loved to get some quick function in order to use them like this :
assertEvent Scheduled (fun e -> Assert.Equal("should produce GameScheduled Event",gameScheduled, e)) result
But to do that I would have the following home made assert function :
let assertEvent<'TEvent> f g result =
match result with
| Choice1Of2(e) ->
match e with
| f(evt) -> g(evt)
| _ -> Assert.None("event not recognised",Some(e))
| Choice2Of2(reason) -> Assert.None("reason",Some(reason))
I was expecting the function f to allow pattern matching on the fly but it does not. Instead I have the following error :
The pattern disciminator 'f' is not defined
Am I doing somthing wrong somewhere ? my fsharp skills are not that high...
A normal function like f can't be used as a pattern discriminator, but you can pass Active Patterns around as arguments:
let assertEvent<'TEvent> (|F|_|) g result =
match result with
| Choice1Of2(e) ->
match e with
| F(evt) -> g(evt)
| _ -> Assert.None("event not recognised",Some(e))
| Choice2Of2(reason) -> Assert.None("reason",Some(reason))
This does, however, require you to also pass an Active Pattern as an argument, which is a bit cumbersome:
assertEvent
(function Scheduled(x) -> Some x | _ -> None)
(fun e -> Assert.Equal("should produce GameScheduled Event",gameScheduled, e))
result
This isn't the way I'd approach the problem, though. What I'd prefer is to write a boolean expression that attempts to pull out and compare the values that I want to verify.
For starters, you could create a little generic helper function to pull out one of the choices from Choice<'a, 'b>:
let toOption1 = function Choice1Of2 x -> Some x | _ -> None
This function has the type Choice<'a,'b> -> 'a option. (I'll leave it as an exercise to define an equivalent toOption2 function.)
Now you can define a boolean expression that pulls out the data if it's there, and compares it with an expected value:
result
|> toOption1
|> Option.map (function Scheduled x -> x | _ -> "")
|> Option.exists ((=) expected)
This is a boolean expression, so you can use Unquote to turn it into an assertion. This is similar to this approach that I've previously described.
I'm looking to use the F# WSDL Type Provider. To call the web service I am using, I need to attach my client credentials to the System.ServiceModel.Description.ClientCredentials.
This is the C# code I have:
var serviceClient = new InvestmentServiceV1Client.InvestmentServiceV1Client();
foreach (ClientCredentials behaviour in serviceClient.Endpoint.Behaviors.OfType<ClientCredentials>())
{
(behaviour).UserName.UserName = USERNAME;
(behaviour).UserName.Password = PASSWORD;
break;
}
This is the F# code I have so far:
let client = new service.ServiceTypes.InvestmentServiceV1Client()
let xxx = client.Endpoint.Behaviors
|> Seq.choose (fun p ->
match box p with
:? System.ServiceModel.Description.ClientCredentials as x -> Some(x)
_ -> None)
|> (System.ServiceModel.Description.ClientCredentials)p.UserName.UserName = USERNAME
Is there an F# equivalent of System.Linq.Enumerable.OfType<T> or should I just use raw OfType<T> ?
I suppose the question is mainly about the break construct, which is not available in F#. Well, the code really just sets the user name and password for the first element of the collection (or none, if the collection is empty). This can be done easily using pattern matching, if you turn the collection to an F# list:
// Get behaviours as in C# and convert them to list using 'List.ofSeq'
let sc = new InvestmentServiceV1Client.InvestmentServiceV1Client()
let behaviours = sc.Endpoint.Behaviors.OfType<ClientCredentials>() |> List.ofSeq
// Now we can use pattern matching to see if there is something in the list
match behaviours with
| behaviour::_ ->
// And if the list is non-empty, set the user name and password
behaviour.UserName.UserName <- USERNAME
behaviour.UserName.Password <- PASSWORD
| _ -> ()
I think you've already implemented the F# equivalent of .OfType(). For emulating the break statement you can do as Tomas does in his answer (matching on list), or you call Seq.head (throws if there are no elements left), or you can do this:
let xxx =
client.Endpoint.Behaviors
|> Seq.choose (function
| :? System.ServiceModel.Description.ClientCredentials as x -> Some x
| _ -> None )
|> Seq.tryPick Some
match xxx with
| Some behavior -> ... // First element of required type found
| None -> ... // No elements of required type at all in sequence