F# - cypher query with multiple return values - f#

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

Related

Does F# support 'call-by-name' semantics?

For a while F# has supported the ability to auto-quote using [<ReflectedDefinitionAttribute>]. Is there anything similar for laziness?
e.g.
member __.Quoted ([<ReflectedDefinitionAttribute>] quotation:Expr<'T>) = ...
member __.Thunked ([<LazyAttribute>] thunk:Lazy<'T>) = ...
I suppose I could use something like
member __.Quoted ([<ReflectedDefinitionAttribute>] quotation:Expr<'T>) =
Lazy (evaluate (<# fun () -> %quotation #>)) // evaluate using Unquote or similar
But wouldn't this be costly?
UPDATE:
I found a hack, it's not exactly what I would like but it give the correct behavior.
type Signal = Signal with
member __.Return x = x
member __.Delay (f:unit -> _) = f
let a = Signal { return randint }
let b = Signal { return randint }
let c = Signal { return a() + b() }
There is nothing like the ReflectedDefinition attribute for automatically turning things into delayed Lazy<'T> computations.
You are right that automatically quoting the argument achieves something like this. You could use the (very limited) LeafExpressionConverter.EvaluateQuotation to do this for some limited kinds of expressions, but as you note, this would be inefficient. The following is a proof of concept though (but you cannot call custom functions in the branches as this uses LINQ expressions):
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers
type A =
static member If<'T>(c:bool,
[<ReflectedDefinition>] t:Expr<'T>,
[<ReflectedDefinition>] f:Expr<'T>) =
if c then LeafExpressionConverter.EvaluateQuotation t :?> 'T
else LeafExpressionConverter.EvaluateQuotation f :?> 'T
A.If(1 = 2, 0, 1)
In practice, I think a more reasonable approach is to just use the built-in Lazy<'T> values. F# has a (not widely known) lazy keyword that gives you a bit nicer syntax for creating those:
let iff c (t:Lazy<_>) (f:Lazy<_>) =
if c then t.Value else f.Value
iff (1 = 2)
(lazy (printfn "true"; 41))
(lazy (printfn "false"; 42))

Is there a way to get Record fields by string in F#?

I would like to get the value of a field in a Record by looking it up with a string.
type Test = { example : string }
let test = { example = "this is the value" }
let getByName (s:string) =
???? //something like test.GetByName(s)
Standard .net reflection should be working fine for such scenario. Record fields are exposed as properties, so you can just query the type with reflection API.
It could look like this:
let getByName (s:string) =
match typeof<Test>.GetProperties() |> Array.tryFind (fun t -> t.Name = s)
with
| Some pi -> Some(pi.GetValue(test))
| None -> None

How do I compose a list of functions?

If I have a type named Person, and list of functions, for example...
let checks = [checkAge; checkWeight; checkHeight]
...where each function is of the type (Person -> bool), and I want to do the equivalent of...
checkAge >> checkWeight >> checkHeight
...but I don't know in advance what functions are in the list, how would I do it?
I tried the following...
checks |> List.reduce (>>)
...but this gives the following error...
error FS0001: Type mismatch. Expecting a
(Person -> bool) -> (Person -> bool) -> Person -> bool
but given a
(Person -> bool) -> (bool -> 'a) -> Person -> 'a
The type 'Person' does not match the type 'bool'
What am I doing wrong?
It looks like Railway oriented programming would be a good fit here.
If you choose to go this route, you basically have two options.
You can either go all in, or the quick route.
Quick route
You rewrite your validation functions to take a Person option instead of just plain Person.
let validAge (record:Record option) =
match record with
| Some rec when rec.Age < 65 && rec.Age > 18 -> record
| None -> None
Now you should be able to easily chain your function.
checks |> List.reduce (>>)
All in
Alternatively, if you are lazy and don't want to match .. with in every validation function, you can write some more code.
(samples taken from [1])
First there's a bit of setup to do.
We'll define a special return type, so we can get meaningful error messages.
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
A bind function, to bind the validations together
let bind switchFunction =
function
| Success s -> switchFunction s
| Failure f -> Failure f
You'll have to rewrite your validation functions as well.
let validAge (record:Record) =
if record.Age < 65 && record.Age > 18 then Success input
else Failure "Not the right age bracket"
Now combine with
checks |> List.reduce (fun acc elem -> acc >> bind elem)
Either way, check out the original article.
There's much more there you might be able to use :)
Edit: I just noticed that I was too slow in writing this answer once again.
Besides, I think Helge explained the concetp better than I did as well.
You may somehow have stumbled upon a dreaded concept. Apperently its the Voldemort (dont say his name!) of functional programming.
With no further ado lets walk right into the code:
type Person =
{ Name : string
Age : int
Weight : int
Height : int }
type Result =
| Ok of Person
| Fail
let bind f m =
match m with
| Ok p -> f p
| _ -> Fail
let (>=>) f1 f2 = f1 >> (bind f2)
let checkAge p =
if p.Age > 18 then Ok(p)
else Fail
let checkWeight p =
if p.Weight < 80 then Ok(p)
else Fail
let checkHeight p =
if p.Height > 150 then Ok(p)
else Fail
let checks = [ checkAge; checkWeight; checkHeight ]
let allcheckfunc = checks |> List.reduce (>=>)
let combinedChecks =
checkAge
>=> checkWeight
>=> checkHeight
let p1 =
{ Name = "p1"
Age = 10
Weight = 20
Height = 110 }
let p2 =
{ Name = "p2"
Age = 19
Weight = 65
Height = 180 }
allcheckfunc p1
combinedChecks p1
allcheckfunc p2
combineChecks p2
At this point I could throw around a lot of weirdo lingo (not really true, I couldnt...), but lets just look at what I have done.
I dropped your return value of bool and went for another type (Result) with either (mark that keyword!) Ok or Fail.
Then made a helper (bind) to wrap and unwrapp stuff from that Result-type.
And a new operator (>=>) to combine the stuff in reduce.
Mind that the first check-function to Fail will shortcut the entire chain and more or less immediately (not calling the other functions) return Fail. In addition you will not know where in this chain it did Fail or which functions ahead of any Fail did actually Ok.
There are methods to also accumulate the errors as you go along, so that you get get a feedback of type: "the checkAge returned Fail, but the others was great success"
The code is mostly stolen from here: http://fsharpforfunandprofit.com/posts/recipe-part2/
And you may want to read about the entire website of Wlaschin and even a lot more to get into the finer and harder details if wanted.
Good luck on your journey to the upper floors of the Ivory Tower. ;-)
Footnote: This is called an Either-monad usually. Its not entirely finished and what not in the above code, but never mind... I think it will work in your case...
The >> operator is useful if you have functions that perform some transformation. For example, if you had a list of functions Person -> Person that turn one person into another.
In your case, it seems that you have functions Person -> bool and you want to build a composed function that returns true if all functions return true.
Using List.reduce you can write:
checks|> List.reduce (fun f g -> (fun p -> f p && g p))
Perhaps an easier option is to just write a function that takes a person and uses List.forall:
let checkAll checks person = checks |> List.forall (fun f -> f person)

What is the correct syntax for RavenDB Search method in F#

I am trying to find all posts in RavenDB containing a word (index is there)
Here is a query that works, finds everything that starts with 'Liv'
let post = query {
for post in session.Query<MyType>() do
where (post.Text.StartsWith("Liv"))
select post
}
An attempt to use string.Contains() method as condition of Where
closure, will throw NotSupportedException.
Here
So I am trying to use Search method where:
Expression<Func<T, object>> fieldSelector,
// Expression marking a field in which terms should be looked for.
C# equivalent from docs:
List<User> users = session
.Query<User>("Users/ByNameAndHobbies")
.Search(x => x.Name, "Adam")
.Search(x => x.Hobbies, "sport")
.ToList();
My first try was to go with
let x = session.Query<MyType>(index).Search((fun xe -> xe.Text ), "Liv")
But getting error because it expects object out. Tried to downcast String to Object (what a strange idea), but getting:
Cannot understand how to translate x => x.Invoke(xe)
At the moment, I am out of ideas. I am supposed to mark field for search and return object. Any ideas?
Thank you.
EDIT 1:
My expression. Gets runtime InvalidCastException because it can't cast string to obj.
let expr =
<# Func<MyType, _>(fun xe -> xe.Text ) #>
|> LeafExpressionConverter.QuotationToExpression
|> unbox<System.Linq.Expressions.Expression<Func<MyType, _>>>
You mentioned that you tried casting the string to object. I tried it using :> obj and it does work.
Here is my working query:
let expr = <# Func<MyType,_>(fun x -> x.Text :> obj ) #>
|> LeafExpressionConverter.QuotationToExpression
|> unbox<Linq.Expressions.Expression<Func<MyType,_>>>
let events = session.Query<MyType>()
.Search(expr, "Liv*", decimal 1, SearchOptions.Or, EscapeQueryOptions.AllowAllWildcards)
|> List.ofSeq

Working with Nullable<'T> in F#

I'm wondering what others have come up with for dealing with Nullable<'T> in F#. I want to use Nullable<'T> on data types so that serialization works properly (i.e., doesn't write out F# option type to XML). But, I don't want my code stuck dealing with the ugliness of dealing with Nullable<'T> directly. Any suggestions?
Is it better to use active patterns to match directly on Nullable, or just a converter to option and use Some/None matching?
Additionally, I'd love to hear ideas on dealing with nullable references in a nice manner too. If I use, say "string option", then I end up with the F# option type wrapping things. If I don't then I can't distinguish between truly optional strings and strings that shouldn't be null.
Any chance .NET 4 will take on an Option<'T> to help out? (If it's part of the BCL, then we might see better support for it...)
As active patterns as options plays nicely with pattern matching, but is seems by using active patterns (i.e. typeof and ??) your code will eat more ticks.
The base question is how you will deal with your nullable references?
In case your code is long chained computations it's nice to use monadic syntax:
type Maybe<'a> = (unit -> 'a option)
let succeed x : Maybe<'a> = fun () -> Some(x)
let fail : Maybe<'a> = fun () -> None
let run (a: Maybe<'a>) = a()
let bind p rest = match run p with None -> fail | Some r -> (rest r)
let delay f = fun () -> run (f ())
type MaybeBuilder() =
member this.Return(x) = succeed x
member this.Let(p,rest) = rest p
member this.Bind(p,rest) = bind p rest
member this.Delay(f) = delay f
let maybe = new MaybeBuilder()
let add (a:'a) (b:'a) =
maybe {
match TryGetNumericAssociation<'a>() with
| Some v -> return (v.Add(a,b))
| _ -> return! fail
}
let add3 (a:'a) (b:'a) (c:'a) =
maybe {
let! ab = add a b
let! abc = add ab c
return abc
}
> let r1 = add 1 2;;
val r1 : (unit -> int option)
> r1();;
val it : int option = Some 3
> let r2 = add "1" "2";;
val r2 : (unit -> string option)
> r2();;
val it : string option = None
> let r3 = add3 "one" "two" "three";;
val r3 : (unit -> string option)
> r3();;
val it : string option = None

Resources