I'm just starting out with F# and .Net but after some Googling I didn't find examples of this. I apologize in advance if this is too simple.
I'm trying to query a database and do it asynchronously. For example, I have a function like so:
let queryExample name =
query {for f in foo do
where (f.name = name)
select f.name}
|> Seq.toList
Now, how would I make an async version of this? query doesn't return an Async<'a> type.
The answer will depend on what you're querying. Many data sources will expose something like a data context that enables running queries in different ways, but this isn't exposed directly on the IQueryable type (and is therefore not something that you can do directly with the result of a query { ... } expression.
As an example, if your foo is a LINQ-to-SQL Table<Foo>, then you can do something like this:
let queryExample name =
let q =
query { for f in foo do
where (f.name = name)
select f.name }
let cmd = foo.Context.GetCommand(q)
async {
let! reader = Async.AwaitTask (cmd.ExecuteReaderAsync())
return foo.Context.Translate<Foo>(reader)
}
This will return an Async<seq<Foo>>. If you'll be running lots of queries like this, then it's easy to extract the meat of this into a reusable mechanism.
I use FSharp.Data.Sql with success http://fsprojects.github.io/SQLProvider/
Seq.executeQueryAsync
Example below shows an easy syntax for doing this. Basically just create an async function with a query expression inside and return the result.
let data = [ 1; 5; 7; 11; 18; 21]
let getEvenInts = fun (arr : list<int> ) -> async {
let q = query {
for N in arr do
where (( N % 2 ) = 0)
select N
}
return q
}
let getOddInts = fun (arr : list<int> ) -> async {
let q = query {
for N in arr do
where (( N % 2 ) <> 0)
select N
}
return q
}
let evens = getEvenInts data |> Async.RunSynchronously
let odds = getOddInts data |> Async.RunSynchronously
printfn "Evens: %A Odds: %A" evens odds
Related
This is not for a practical need, but rather to try to learn something.
I am using FSToolKit's asyncResult expression which is very handy and I would like to know if there is a way to 'combine' expressions, such as async and result here, or does a custom expression have to be written?
Here is an example of my function to set the ip to a subdomain, with CloudFlare:
let setSubdomainToIpAsync zoneName url ip =
let decodeResult (r: CloudFlareResult<'a>) =
match r.Success with
| true -> Ok r.Result
| false -> Error r.Errors.[0].Message
let getZoneAsync (client: CloudFlareClient) =
asyncResult {
let! r = client.Zones.GetAsync()
let! d = decodeResult r
return!
match d |> Seq.filter (fun x -> x.Name = zoneName) |> Seq.toList with
| z::_ -> Ok z // take the first one
| _ -> Error $"zone '{zoneName}' not found"
}
let getRecordsAsync (client: CloudFlareClient) zoneId =
asyncResult {
let! r = client.Zones.DnsRecords.GetAsync(zoneId)
return! decodeResult r
}
let updateRecordAsync (client: CloudFlareClient) zoneId (records: DnsRecord seq) =
asyncResult {
return!
match records |> Seq.filter (fun x -> x.Name = url) |> Seq.toList with
| r::_ -> client.Zones.DnsRecords.UpdateAsync(zoneId, r.Id, ModifiedDnsRecord(Name = url, Content = ip, Type = DnsRecordType.A, Proxied = true))
| [] -> client.Zones.DnsRecords.AddAsync(zoneId, NewDnsRecord(Name = url, Content = ip, Proxied = true))
}
asyncResult {
use client = new CloudFlareClient(Credentials.CloudFlare.Email, Credentials.CloudFlare.Key)
let! zone = getZoneAsync client
let! records = getRecordsAsync client zone.Id
let! update = updateRecordAsync client zone.Id records
return! decodeResult update
}
It is interfacing with a C# lib that handles all the calls to the CloudFlare API and returns a CloudFlareResult object which has a success flag, a result and an error.
I remapped that type to a Result<'a, string> type:
let decodeResult (r: CloudFlareResult<'a>) =
match r.Success with
| true -> Ok r.Result
| false -> Error r.Errors.[0].Message
And I could write an expression for it (hypothetically since I've been using them but haven't written my own yet), but then I would be happy to have an asyncCloudFlareResult expression, or even an asyncCloudFlareResultOrResult expression, if that makes sense.
I am wondering if there is a mechanism to combine expressions together, the same way FSToolKit does (although I suspect it's just custom code there).
Again, this is a question to learn something, not about the practicality since it would probably add more code than it's worth.
Following Gus' comment, I realized it would be good to illustrate the point with some simpler code:
function DoA : int -> Async<AWSCallResult<int, string>>
function DoB : int -> Async<Result<int, string>>
AWSCallResultAndResult {
let! a = DoA 3
let! b = DoB a
return b
}
in this example I would end up with two types that can take an int and return an error string, but they are different. Both have their expressions so I can chain them as needed.
And the original question is about how these can be combined together.
It's possible to extend CEs with overloads.
The example below makes it possible to use the CustomResult type with a usual result builder.
open FsToolkit.ErrorHandling
type CustomResult<'T, 'TError> =
{ IsError: bool
Error: 'TError
Value: 'T }
type ResultBuilder with
member inline _.Source(result : CustomResult<'T, 'TError>) =
if result.IsError then
Error result.Error
else
Ok result.Value
let computeA () = Ok 42
let computeB () = Ok 23
let computeC () =
{ CustomResult.Error = "oops. This went wrong"
CustomResult.IsError = true
CustomResult.Value = 64 }
let computedResult =
result {
let! a = computeA ()
let! b = computeB ()
let! c = computeC ()
return a + b + c
}
I'm trying to do the following in F#, from pseudo C# code:
Data? MyFunc(a, b, c) { ... }
var result = new List<Data>();
foreach (var i in MyData)
{
var r = MyFunc(something, somethingelse, i);
if (r != null) result.add((Data)r);
}
I have 2 questions:
Is there an equivalent of List.filter that will allow to check if the result of my function call is None or not?
How can I invoke a function through a list if some of the parameters do not come from the list iterator? like something and somethingelse in my example?
(beginning in F#, the answer may be trivial)
You can use List.choose:
let myData a b c = ...
let collect somthing somethingElse myData =
myData |> List.choose (myFunc something somethingElse)
If the list element is not the last element to myFunc you can't use partial application but can use a function e.g.
myData |> List.choose (fun e -> myFunc something e somethingElse)
I am new to F#. I am trying to use List.fold to help me generate a list of categories and sub-categories based on their Id and ParentId fields. It seems I probably made this code more complex than need be, as I'm getting the stackoverflow error. What am I doing wrong or missing? All related feedback is appreciated.
// types
type CategoryStructure = {
Id: ValidString;
ParentId: ValidString;
Name: ValidString;
Abbreviation: ValidString;
Description: ValidString;
SapId: ValidString;
Section: ValidString;
SectionPosition: ValidString
}
type DynamicCategories = {
Category: CategoryStructure;
SubCategories: seq<DynamicCategories>
}
// this is the function that produces the stack overflow error
let rec private structureCategories (fullList: CategoryStructure list)
(list: CategoryStructure list) =
List.fold (fun acc elem ->
// get all categories and details
let categories = fullList
let mainAcc =
[
for row in categories do
if row = elem
then
let subs =
List.fold (fun acc' elem' ->
if row.Id = elem'.ParentStructureId
then
let foundSubCategory =
{
Category = elem';
SubCategories = structureCategories fullList list |> Seq.ofList
}
foundSubCategory :: acc'
else acc'
) List.empty<DynamicCategories> categories
|> Seq.ofList
yield{
Category = elem;
SubCategories = subs
}
]
mainAcc # acc
) List.empty<DynamicCategories> list
// this function gets the initial parent categories and calls the above function
let getStructuredCategories () =
let categories = allCategoriesAndDetails () |> List.ofSeq
[
for row in categories do
if row.ParentStructureId = NotValid
then yield row
] |> structureCategories categories |> Seq.ofList
You keep calling structureCategories with the same arguments - fullList and list. Since arguments are same, it proceeds to do exactly the same thing as on the previous pass, and ends up calling itself again, with the same arguments. And so on.
This is unbounded recursion ("unbounded" here means "doesn't know when to stop recurring"), and it is also not "tail recursion", so quite naturally, it causes stack overflow.
If you want to turn the flat list into a tree-like structure, you could do a bit simpler than this:
let getChildren fullList parentId = fullList |> List.filter (fun c -> c.ParentId = parentId)
let rec toTree fullList root =
{ Category = root;
SubCategories =
getChildren fullList root.Id
|> List.map (toTree fullList) }
With this, you'll be left with two problems, which I don't know how to solve without knowing more about your requirements:
This will still cause stack overflow if the original list happens to have cycles.
You need to decide who the root(s) of the tree is (or are). Intuitively, this would be indicated via "empty" ParentId, but it is unclear from your data structure what "empty" means.
And finally, this naive solution, while better than your original one, is still a bit slower than it needs to be. It iterates over the whole list once, and for every node does another pass to determine its children, resulting in overall complexity of O(N^2). This may be fine if you expect relatively small list, but not so fine for larger lists. In that case, I would first turn the list into a hashtable (keyed by ParentId) and then use that to find children instead of List.filter.
Thanks to Fyodor, I saw my mistake. He was dead on about calling the same arguments. I added this bit of code right before the foundSubCategory value:
let modifiedList = elem' :: List.empty<CategoryStructure>
and then called that value in the subsequent code:
let foundSubCategory =
{
Category = elem';
SubCategories = structureCategories fullList modifiedList |> Seq.ofList
}
This solved my issue, but now as Fyodor alluded to, I now have to refactor this into something more efficient.
UPDATE
With the insight that Fyodor pointed out this is the current state of my code, which replaces the original code:
let getStructuredCategories () =
let fullList = allCategoriesAndDetails ()
let parentList () =
allCategoriesAndDetails ()
|> Seq.filter (fun p -> p.ParentStructureId = NotValid)
let rec toTree (fullList': seq<CategoryStructure>) (parent: CategoryStructure) =
fullList'
|> Seq.filter (fun x -> x.ParentStructureId = parent.Id)
|> Seq.map (fun x ->
{
Category = x;
SubCategories =
toTree fullList' x
})
seq {
for row in parentList () do
yield {
Category = row;
SubCategories = toTree fullList row
}
}
Given this query (from here)
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return<Person>("e")
.Results
.Select(fun x -> x.Name)
I would like to tweak it and have it return multiple values packaged together.
Not sure about how the type should look:
let pAfollowers =
client.Cypher
.Match("n<-[r:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return<???>("n, r, e")
Secondly I was wondering if it is possible to have a return statement after a CreateUnique.
I am trying to tweak this query:
let knows target (details : Knows) source =
client.Cypher
.Match("(s:Person)", "(t:Person)")
.Where(fun s -> s.Twitter = source.Twitter)
.AndWhere(fun t -> t.Twitter = target.Twitter)
.CreateUnique("s-[:knows {knowsData}]->t")
.WithParam("knowsData", details)
.ExecuteWithoutResults()
to have it return s, t and the details.
OK, good news / bad news - though in practice the good is tempered with bad :(
Good first:
You can return after a CreateUnique, something like:
.CreateUnique("s-[:Knows {knowsData}]-t")
.WithParam("knowsData", details)
.Returns<???>( "s,t" )
.Results;
Bad news:
The bad news is that you probably can't do it in F#. Neo4jClient requires you to use either object initializers, or anonymous types to cast the data, so you could try something like:
type FollowingResults = { Follower : Person; Followed : Person;}
let createExpression quotationExpression = LeafExpressionConverter.QuotationToLambdaExpression quotationExpression
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return(createExpression <# Func<ICypherResultItem, ICypherResultItem, FollowingResults>(fun (e : Cypher.ICypherResultItem) (n : Cypher.ICypherResultItem) -> {Follower = e.As<Person>(); Followed = n.As<Person>()}) #>)
.Results
.Select(fun x -> x)
for follower in pAfollowers do
printfn "%s followed %s" follower.Follower.Name follower.Followed.Name
For which the F# compiler will have no problems at all. However, Neo4jClient will throw an Argument exception with the following message:
The expression must be constructed as either an object initializer (for example: n => new MyResultType { Foo = n.Bar }), an anonymous type initializer (for example: n => new { Foo = n.Bar }), a method call (for example: n => n.Count()), or a member accessor (for example: n => n.As().Bar). You cannot supply blocks of code (for example: n => { var a = n + 1; return a; }) or use constructors with arguments (for example: n => new Foo(n)).
The problem being, F# doesn't have object initializers, nor anonymous types, you can wrangle with the F# stuff for ages and not get anywhere, as the C# doesn't recognize the F# initialization.
I have somewhat good news to both. This code will compile just fine using tuples and can be used with a modified Neo4jClient that supports F# Tuples: https://github.com/n074v41l4bl34u/Neo4jClient Solution is based on: https://fsharppowerpack.codeplex.com/workitem/4572
let knows target (details : Knows) source =
client.Cypher
.Match("(s:Person)", "(t:Person)")
.Where(fun s -> s.Twitter = source.Twitter)
.AndWhere(fun t -> t.Twitter = target.Twitter)
.CreateUnique("s-[:knows {knowsData}]->t")
.WithParam("knowsData", details)
.Return(fun s t -> s.As<Person>(),t.As<Person>())
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return(fun (e : Cypher.ICypherResultItem) n -> e.As<Person>().Name,n.As<Person>().Name)
The type annotation on '(e : Cypher.ICypherResultItem)' can be omited when using more than one argument in fun.
However, when using a single argument, this gets rid off the ugly createExpression <# Func(...) #>) syntax.
For details on why look on the bottom of this page: https://gist.github.com/cskardon/8300420
What would be an elegant way to implement the functionality of this nested class in F#?
private class Aliaser {
private int _count;
internal Aliaser() { }
internal string GetNextAlias() {
return "t" + (_count++).ToString();
}
}
This was my first attempt, but it feels like there should be a sexy one-liner for this:
let aliases = (Seq.initInfinite (sprintf "t%d")).GetEnumerator()
let getNextAlias() =
aliases.MoveNext() |> ignore
aliases.Current
The usual way of writing is to create a function with local state captured in a closure:
let getNextAlias =
let count = ref 0
(fun () ->
count := !count + 1;
sprintf "t%d" (!count))
The type of getNextAlias is simply unit -> string and when you call it repeatedly, it returns strings "t1", "t2", ... This relies on mutable state, but the mutable state is hidden from the user.
Regarding whether you can do this without mutable state - the simple answer is NO, because when you call a purely functional function with the same parameter twice, it must return the same result. Thus, you'd have to write something with the following structure:
let alias, state1 = getNextAlias state0
printf "first alias %s" alias
let alias, state2 = getNextAlias state1
printf "second alias %s" alias
// ...
As you can see, you'd need to keep some state and maintain it through the whole code. In F#, the standard way of dealing with this is to use mutable state. In Haskell, you could use State monad, which allows you to hide the passing of the state. Using the implementation from this question, you could write something like:
let getNextAlias = state {
let! n = getState
do! setState (n + 1)
return sprintf "t%d" n }
let program =
state {
let! alias1 = getNextAlias()
let! alias2 = getNextAlias()
// ...
}
execute progam 0 // execute with initial state
This is quite similar to other computations such as lazy or seq, actually - computations in the state { .. } block have some state and you can execute them by providing initial value of the state. However, unless you have good reasons for requiring purely functional solution, I'd prefer the first version for practical F# programming.
Here is the quick and dirty translation
type Aliaser () =
let mutable _count = 0
member x.GetNextAlias() =
let value = _count.ToString()
_count <- _count + 1
"t" + value
A more functional approach without state is to use continuations.
let createAliaser callWithValue =
let rec inner count =
let value = "t" + (count.ToString())
callWithValue value (fun () -> inner (count + 1))
inner 1
This is a declaration which will call the function callWithValue with both the value and the function to execute to repeat with the next value.
And here's an example using it
let main () =
let inner value (next : unit -> unit )=
printfn "Value: %s" value
let input = System.Console.ReadLine()
if input <> "quit" then next()
createAliaser inner
main()
I would use Seq.unfold : (('a -> ('b * 'a) option) -> 'a -> seq<'b>) to generate the aliases.
Implemented as:
let alias =
Seq.unfold (fun count -> Some(sprintf "t%i" count, count+1)) 0