Consider these 3 versions
async {
return! retrieved =
client
|> get tagIdOfQid None
|> Async.Catch
|> Async.map (function
| Choice1Of2 doc ->
doc
|> mapDoc
|> function
| IdOfQ d -> d
| _ -> defaultTagIdOfQ
| _ -> defaultTagIdOfQ)
}
async {
return retrieved =
client
|> get tagIdOfQid None
|> Async.Catch
|> Async.RunSynchronously
|> function
| Choice1Of2 doc ->
doc
|> mapDoc
|> function
| IdOfQ d -> d
| _ -> defaultTagIdOfQ
| _ -> defaultTagIdOfQ)
}
async {
let! retrieved =
client
|> get tagIdOfQid None
|> Async.Catch
return! retrieved
|> function
| Choice1Of2 doc ->
doc
|> mapDoc
|> function
| IdOfQ d -> d
| _ -> defaultTagIdOfQ
| _ -> defaultTagIdOfQ
}
I want to pipe the result of the get to another computation, I can use Async.map, Async.RunSynchronously or add multiple let! bindings.
I see them all as valid alternatives for doing the same, without any differences, but maybe I'm wrong and they are doing slightly different things.
Is there any tradeoff between Async.map, Async.RunSynchronously and let!?
The key difference is that if you use Async.RunSynchronously, even if this is inside another async workflow, this will block a thread when you run it. Using Async.map will not block and multiple let! is the same in this respect.
So, I would avoid using Async.RunSynchronously. As to what else to do, this is a style preference.
Using async { return! e } does not make sense, because it means exactly the same as just e, so you can simplify the first approach. I also replaced the confusing (to me at least) inner pipe with ordinary match:
client
|> get tagIdOfQid None
|> Async.Catch
|> Async.map (function
| Choice1Of2 doc ->
match mapDoc doc with
| IdOfQ d -> d
| _ -> defaultTagIdOfQ
| _ -> defaultTagIdOfQ)
In the second approach, I would also remove some of the pipelines, because I find them hard to follow. If you are inside async you can also use ordinary try ... with instead of Async.Catch:
async {
try
let! doc = get tagIdOfQid None client
match mapDoc doc with
| IdOfQ d -> return d
| _ -> return defaultTagIdOfQ
with _ -> return defaultTagIdOfQ
}
If I was writing this, I would go with the latter - mainly because it is very easy to read & understand what is going on.
Related
with this union:
type T =
| A
| B
| C
and a T list
I would like to implement something like this pseudo code:
let countOfType (t: Type) (l: T list) =
l
|> List.filter (fun x -> x.GetType() = t)
|> List.length
when I would pass if I want to count the 'A', 'B', etc..
but A.GetType() and B.GetType() return the T type, so this doesn't work.
Is there a way where I could check the type by passing it as a parameter?
The practical case here is that I have a Map that gets updated every few seconds and its values are part of the same DU. I need to be able to see how many of each type, without having to update the code (like a match block) each time an entry gets added.
Addendum:
I simplified the original question too much and realized it after seeing Fyodor's answer.
So I would like to add the additional part:
how could this also be done for cases like these:
type T =
| A of int
| B of string
| C of SomeOtherType
For such enum type T as you specified, you can just use regular comparison:
let countOfType t (l: T list) =
l
|> List.filter (fun x -> x = t)
|> List.length
Usage:
> countOfType A [A; A; B; C; A]
3
> countOfType B [A; A; B; C; A]
1
Try List.choose: ('a -> 'b option) -> 'a list -> 'b list, it filters list based on 'a -> 'b option selector. If selectors evaluates to Some, then value will be included, if selector evaluates to None, then value will be skipped. If you worry about allocations caused by instantiation of Some, then you'll have to implement version that will use ValueOption
let onlyA lis =
lis |> List.choose (function
| (A _) as a -> Some a
| _ -> None)
let onlyB lis =
lis |> List.choose (function
| (B _) as b -> Some b
| _ -> None)
let lis = [
A 1
A 22
A 333
B ""
B "123"
]
lis |> onlyA |> List.length |> printfn "%d"
You can pattern match, and throw away the data, to create a function for the filter.
type T =
| A of int
| B of string
| C of float
[A 3;A 1;B "foo";B "bar";C 3.1; C 4.6]
|> List.filter (fun x ->
match x with
| A _ -> true
| B _ -> false
| C _ -> false
)
|> List.length
But in general i would asume, that you create a predicate function in your modul.
let isA x =
match x with
| A _ -> true
| _ -> false
if you have those functions you can just write
[A 3;A 1;B "foo";B "bar";C 3.1; C 4.6]
|> List.filter isA
|> List.length
Hi I have the following code which works as I expect but the compiler warns me about incomplete pattern matching when I pattern match in the Option.defaultWith function. Is there a smarter way to achieve the same effect but without warnings?
I have been thinking about throwing an exception for the rest of the cases but that's pretty ugly.
namespace JsonParser
open System
open System.Globalization
open FSharp.Data
open FSharp.Data.Runtime
type public Key = string
type public Value =
| Int of int
| Double of double
| Decimal of decimal
| String of string
| DateTime of DateTime
| Boolean of Boolean
| Array of Value []
| Guid of Guid
| Null
| Object of Record []
and public Record =
{ Key: Key
Value: Value }
module public Json =
let private culture = CultureInfo.InvariantCulture
let private emptyArray = Array.empty<String>
let rec private map (value: JsonValue) =
JsonConversions.AsInteger culture value
|> Option.map Value.Int
|> Option.orElseWith (fun () -> JsonConversions.AsDecimal culture value |> Option.map Value.Decimal)
|> Option.orElseWith (fun () -> JsonConversions.AsFloat emptyArray true culture value |> Option.map Decimal |> Option.map Value.Decimal)
|> Option.orElseWith (fun () -> JsonConversions.AsGuid value |> Option.map Value.Guid)
|> Option.orElseWith (fun () -> JsonConversions.AsDateTime culture value |> Option.map Value.DateTime)
|> Option.orElseWith (fun () -> JsonConversions.AsBoolean value |> Option.map Value.Boolean)
|> Option.defaultWith (fun () ->
match value with
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x ->
x
|> Array.map map
|> Value.Array
| JsonValue.Record x ->
x
|> Array.map (fun (x, y) ->
{ Key = x
Value = map y })
|> Value.Object)
The answer really depends on how you want to handle various corner cases in your JSON data.
The operations in JsonConversions are implemented in a way where they attempt to convert the value to the target type whenever this can reasonably be done. This means that using those, a value true, 1 and "yes" will all be converted to boolan true. Is this what you want? If so, then I would probably just add a case to the pattern match that throws an exception, saying that the situation should not happen:
match value with
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x -> (...)
| JsonValue.Record x -> (...)
| JsonValue.Float _ | JsonValue.Number _ | JsonValue.Boolean _ ->
failwith "should never happen: Numbers and booleans handled earlier!"
If you want to turn JSON value "yes" to Value.String("yes") rather than to Value.Boolean(true), then it is a lot easier if you directly pattern match on JsonValue:
let rec private map (value: JsonValue) =
match value with
| JsonValue.Float f -> Value.Double f
| JsonValue.Number n -> Value.Decimal n
| JsonValue.Boolean b -> Value.Boolean b
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x ->
x |> Array.map map |> Value.Array
| JsonValue.Record x ->
x |> Array.map (fun (x, y) -> { Key = x; Value = map y }) |> Value.Object
You can find the details about how JsonConversions work by looking at the relevant file in the source code: JsonConversions and TextConversions.
I like using ROP when I have to deal with IO/Parsing strings/...
However let's say that I have a function taking 2 parameters. How can you do clean/readable partial application when your 2 parameters are already a Result<'a,'b> (not necessary same 'a, 'b)?
For now, what I do is that I use tuple to pass parameters and use the function below to get a Result of a tuple so I can then bind my function with this "tuple-parameter".
/// Transform a tuple of Result in a Result of tuple
let tupleAllResult x =
match (fst x, snd x) with
| Result.Ok a, Result.Ok b -> (a,b) |> Result.Ok
| Result.Ok a, Result.Error b -> b |> Result.Error
| Result.Error a, _ -> a |> Result.Error
let f (a: 'T, b: 'U) = // something
(A, B) |> tupleAllResult
|> (Result.bind f)
Any good idea?
Here what I wrote, which works but might not be the most elegant
let resultFunc (f: Result<('a -> Result<'b, 'c>), 'd>) a =
match f with
| Result.Ok g -> (g a) |> Result.Ok |> Result.flatten
| Result.Error e -> e |> Result.Error |> Result.flatten
I am not seeing partial application in your example, a concept related to currying and argument passing -- that's why I am assuming that you are after the monadic apply, in that you want to transform a function wrapped as a Result value into a function that takes a Result and returns another Result.
let (.>>.) aR bR = // This is "tupleAllResult" under a different name
match aR, bR with
| Ok a, Ok b -> Ok(a, b)
| Error e, _ | _, Error e -> Error e
// val ( .>>. ) : aR:Result<'a,'b> -> bR:Result<'c,'b> -> Result<('a * 'c),'b>
let (<*>) fR xR = // This is another name for "apply"
(fR .>>. xR) |> Result.map (fun (f, x) -> f x)
// val ( <*> ) : fR:Result<('a -> 'b),'c> -> xR:Result<'a,'c> -> Result<'b,'c>
The difference to what you have in your question is map instead of bind in the last line.
Now you can start to lift functions into the Result world:
let lift2 f xR yR =
Ok f <*> xR <*> yR
// val lift2 :
// f:('a -> 'b -> 'c) -> xR:Result<'a,'d> -> yR:Result<'b,'d> -> Result<'c,'d>
let res : Result<_,unit> = lift2 (+) (Ok 1) (Ok 2)
// val res : Result<int,unit> = Ok 3
I'm learning F# and I've started to play around with both sequences and match expressions.
I'm writing a web scraper that's looking through HTML similar to the following and taking the last URL in a parent <span> with the paging class.
<html>
<body>
<span class="paging">
Link to Google
The Link I want
</span>
</body>
</html>
My attempt to get the last URL is as follows:
type AnHtmlPage = FSharp.Data.HtmlProvider<"http://somesite.com">
let findMaxPageNumber (page:AnHtmlPage)=
page.Html.Descendants()
|> Seq.filter(fun n -> n.HasClass("paging"))
|> Seq.collect(fun n -> n.Descendants() |> Seq.filter(fun m -> m.HasName("a")))
|> Seq.last
|> fun n -> n.AttributeValue("href")
However I'm running into issues when the class I'm searching for is absent from the page. In particular I get ArgumentExceptions with the message: Additional information: The input sequence was empty.
My first thought was to build another function that matched empty sequences and returned an empty string when the paging class wasn't found on a page.
let findUrlOrReturnEmptyString (span:seq<HtmlNode>) =
match span with
| Seq.empty -> String.Empty // <----- This is invalid
| span -> span
|> Seq.collect(fun (n:HtmlNode) -> n.Descendants() |> Seq.filter(fun m -> m.HasName("a")))
|> Seq.last
|> fun n -> n.AttributeValue("href")
let findMaxPageNumber (page:AnHtmlPage)=
page.Html.Descendants()
|> Seq.filter(fun n -> n.HasClass("paging"))
|> findUrlOrReturnEmptyStrin
My issue is now that Seq.Empty is not a literal and cannot be used in a pattern. Most examples with pattern matching specify empty lists [] in their patterns so I'm wondering: How can I use a similar approach and match empty sequences?
The suggestion that ildjarn gave in the comments is a good one: if you feel that using match would create more readable code, then make an active pattern to check for empty seqs:
let (|EmptySeq|_|) a = if Seq.isEmpty a then Some () else None
let s0 = Seq.empty<int>
match s0 with
| EmptySeq -> "empty"
| _ -> "not empty"
Run that in F# interactive, and the result will be "empty".
You can use a when guard to further qualify the case:
match span with
| sequence when Seq.isEmpty sequence -> String.Empty
| span -> span
|> Seq.collect (fun (n: HtmlNode) ->
n.Descendants()
|> Seq.filter (fun m -> m.HasName("a")))
|> Seq.last
|> fun n -> n.AttributeValue("href")
ildjarn is correct in that in this case, an if...then...else may be the more readable alternative, though.
Use a guard clause
match myseq with
| s when Seq.isEmpty s -> "empty"
| _ -> "not empty"
Building on the answer from #rmunn, you can make a more general sequence equality active pattern.
let (|Seq|_|) test input =
if Seq.compareWith Operators.compare input test = 0
then Some ()
else None
match [] with
| Seq [] -> "empty"
| _ -> "not empty"
I've been working with FParsec lately and I found that the lack of generic parsers is a major stopping point for me. My goal for this little library is simplicity as well as support for generic input. Can you think of any additions that would improve this or is anything particularly bad?
open LazyList
type State<'a, 'b> (input:LazyList<'a>, data:'b) =
member this.Input = input
member this.Data = data
type Result<'a, 'b, 'c> =
| Success of 'c * State<'a, 'b>
| Failure of string * State<'a, 'b>
type Parser<'a,'b, 'c> = State<'a, 'b> -> Result<'a, 'b, 'c>
let (>>=) left right state =
match left state with
| Success (result, state) -> (right result) state
| Failure (message, _) -> Result<'a, 'b, 'd>.Failure (message, state)
let (<|>) left right state =
match left state with
| Success (_, _) as result -> result
| Failure (_, _) -> right state
let (|>>) parser transform state =
match parser state with
| Success (result, state) -> Success (transform result, state)
| Failure (message, _) -> Failure (message, state)
let (<?>) parser errorMessage state =
match parser state with
| Success (_, _) as result -> result
| Failure (_, _) -> Failure (errorMessage, state)
type ParseMonad() =
member this.Bind (f, g) = f >>= g
member this.Return x s = Success(x, s)
member this.Zero () s = Failure("", s)
member this.Delay (f:unit -> Parser<_,_,_>) = f()
let parse = ParseMonad()
Backtracking
Surprisingly it didn't take too much code to implement what you describe. It is a bit sloppy but seems to work quite well.
let (>>=) left right state =
seq {
for res in left state do
match res with
| Success(v, s) ->
let v =
right v s
|> List.tryFind (
fun res ->
match res with
| Success (_, _) -> true
| _ -> false
)
match v with
| Some v -> yield v
| None -> ()
} |> Seq.toList
let (<|>) left right state =
left state # right state
Backtracking Part 2
Switched around the code to use lazy lists and tail-call optimized recursion.
let (>>=) left right state =
let rec readRight lst =
match lst with
| Cons (x, xs) ->
match x with
| Success (r, s) as q -> LazyList.ofList [q]
| Failure (m, s) -> readRight xs
| Nil -> LazyList.empty<Result<'a, 'b, 'd>>
let rec readLeft lst =
match lst with
| Cons (x, xs) ->
match x with
| Success (r, s) ->
match readRight (right r s) with
| Cons (x, xs) ->
match x with
| Success (r, s) as q -> LazyList.ofList [q]
| Failure (m, s) -> readRight xs
| Nil -> readLeft xs
| Failure (m, s) -> readLeft xs
| Nil -> LazyList.empty<Result<'a, 'b, 'd>>
readLeft (left state)
let (<|>) (left:Parser<'a, 'b, 'c>) (right:Parser<'a, 'b, 'c>) state =
LazyList.delayed (fun () -> left state)
|> LazyList.append
<| LazyList.delayed (fun () -> right state)
I think that one important design decision that you'll need to make is whether you want to support backtracking in your parsers or not (I don't remember much about parsing theory, but this probably specifies the types of languages that your parser can handle).
Backtracking. In your implementation, a parser can either fail (the Failure case) or produce exactly one result (the Success case). An alternative option is to generate zero or more results (for example, represent results as seq<'c>). Sorry if this is something you already considered :-), but anyway...
The difference is that your parser always follows the first possible option. For example, if you write something like the following:
let! s1 = (str "ab" <|> str "a")
let! s2 = str "bcd"
Using your implementation, this will fail for input "abcd". It will choose the first branch of the <|> operator, which will then process first two characters and the next parser in the sequence will fail. An implementation based on sequences would be able to backtrack and follow the second path in <|> and parse the input.
Combine. Another idea that occurs to me is that you could also add Combine member to your parser computation builder. This is a bit subtle (because you need to understand how computation expressions are translated), but it can be sometimes useful. If you add:
member x.Combine(a, b) = a <|> b
member x.ReturnFrom(p) = p
You can then write recursive parsers nicely:
let rec many p acc =
parser { let! r = p // Parse 'p' at least once
return! many p (r::acc) // Try parsing 'p' multiple times
return r::acc |> List.rev } // If fails, return the result