I want to create a flow that creates a new source (it will be a persistence query) out of incoming elements, and then flattens the results. Something like this simplified example:
var z = Source.Single(1).ConcatMany(i => Source.Single(i));
this code compiles and works as expected. My problem is that when I translate it to F#:
let z = Source.Single(1).ConcatMany(fun i -> Source.Single(i))
I get an error saying
This expression was expected to have type
'IGraph<SourceShape<'a>,Akka.NotUsed>'
but here has type
'Source<int,Akka.NotUsed>'
I think that the cause of that is that F# handles co/contravariance differently than C# and cannot simply convert these generic specializations (https://github.com/fsharp/fslang-suggestions/issues/162), but I cannot figure out a way to make a convertion between an int and a SourceShape<int>. Is it possible to convert this example to F#?
Looking at the code on GitHub, it appears that Source<TOut, TMat> is a direct implementation of IGraph, so you should just be able to cast it:
public sealed class Source<TOut, TMat> : IFlow<TOut, TMat>, IGraph<SourceShape<TOut>, TMat>
let z = Source.Single(1).ConcatMany(fun i -> Source.Single(i) :> IGraph<SourceShape<int>,Akka.NotUsed>)
I think the biggest difference between the C# and F# usage is that C# will automatically do the upcast for you.
One workaround that I found is to use Akkling.Streams wrapper library:
open Akkling.Streams
let x =
Source.singleton 1
|> Source.collectMap(fun x -> Source.singleton x)
the question how to do this without Akkling remains open.
Related
I'm using the following code snippet in a WPF / FsXaml application:
let groupSelected(e: SelectionChangedEventArgs) =
e.AddedItems
|> Seq.cast<string>
|> Seq.head
|> SelectedGroupChanged
let GroupSelected = groupSelected
When I mouse-over groupSelected, Visual Studio shows the following:
val groupSelected: e:SelectionChangedEventArgs -> ClientGroupEvent
It is slightly different for GroupSelected:
val GroupSelected: (SelectionChangedEventArgs -> ClientGroupEvent)
I have noticed this difference before in other contexts and never thought much of it. If I want to invoke either one, the syntax in my code is the same... groupSelected(e) and GroupSelected(e) both compile fine.
However, when I try to use these two from XAML only this works:
{x:Static local:EventConverters.GroupSelected}
This does not work:
{x:Static local:EventConverters.groupSelected}
What is the difference between those two such that XAML Static extension only works with the second? I would have (mistakenly?) thought they were the same thing.
This is one of the areas where simple functional ideas are made a bit more complicated by living in the .NET framework world. F# indeed compiles your groupSelected and GroupSelected in two different ways.
The IntelliSense does tell you this. Most of the time, this is not something you need to worry about, and it is quite sensible to see the following two as the same thing (and, as far as F# itself is concerned, they are):
val groupSelected: e:SelectionChangedEventArgs -> ClientGroupEvent
val GroupSelected: (SelectionChangedEventArgs -> ClientGroupEvent)
The key difference is that the two will be compiled diferently. The first one as a method and the second one as a property that returns a function value. Using C# notation:
// groupSelected is compiled as a method:
ClientGroupEvent groupSelected(SelectionChangedEventArgs e);
// GroupSelected is compiled as a property:
FSharpFunc<SelectionChangedEventArgs, ClientGroupEvent> GroupSelected { get; }
I have the following code:
open NSubstitute
type MyClass()=
let myObject = Substitute.For<IMyInterface>()
do myObject.MyProperty.Returns(true)
do myObject.MyMethod().Returns(true)
On "Returns" (both) I get the error that is not defined. The equivalent C# code works without issue. Adding |> ignore at the end of the do lines does not help. Am I missing something there?
I know you wrote that adding |> ignore at the end doesn't help, but this compiles on my machine:
type IMyInterface =
abstract MyProperty : bool with get, set
abstract member MyMethod : unit -> bool
open NSubstitute
type MyClass() =
let myObject = Substitute.For<IMyInterface>()
do myObject.MyProperty.Returns(true) |> ignore
do myObject.MyMethod().Returns(true) |> ignore
I attempted to infer the definition of IMyInterface from the question; did I get it wrong?
So after I tried the code (Mark Seemann's, as to avoid my C# class) on VS2012, fsi, through direct compilation with fsc and on VS2013, the issue is clearly a VS2012 problem. The code works correctly with the other three.
Not sure yet if it is using a different version of F#. Will need further investigation. But at least, for now, on VS2012 I can use:
do SubstituteExtensions.Returns(myObject.MyProperty, true) |> ignore
It works as well when I need to pass parameters to methods.
I'm creating a module that will be used by C# code, so I would rather not return the LazyList<> directly. If I did, the C# would have to reference the FSharp.PowerPack, which seems strange.
So I would rather return a IList<>, but when I try to do something like:
let x = LazyList.ofSeq {0..10}
let y = x :> IList<int32>
However, this gives me the error:
The type 'LazyList<int> is not compatible with the type 'IList<int>'
This leads me to believe that LazyList<> does NOT implement IList<>. Is this true?
What am I missing?
It is true, LazyList does not implement the IList interface. It implements IEnumerable though.
[<Sealed>]
type LazyList<'T> =
interface IEnumerable<'T>
interface System.Collections.IEnumerable
I sometimes have the need to get the function itself, not the value, of a zero-parameter function in F#, for instance for memoization. I.e., I have this:
let memoize (f: 'a -> 'b) =
let dict = new Dictionary<'a, 'b>()
let memoizedFunc (input: 'a) =
match dict.TryGetValue(input) with
| true, x -> x
| false, _ ->
let answer = f input
dict.Add(input, answer)
answer
memoizedFunc
and this works perfectly, but now I have the following function:
let private getDataSlowOperation =
// implementation
and when I try to memoize that, it gives a type mismatch (essentially the mismatch between the return type of getDataSlowOperation and the 'a type). I can solve this by changing the function as follows:
let private getDataSlowOperation bogus =
// implementation
Now this works, but it seems odd to have to change the function signature to get memoization to work:
let memoGetDataSlowOperation = memoize getDataSlowOperation
I've experimented with inline fun declarations, but this creates, of course, a new anonymous function and the memoization doesn't work with that. Any ideas how to resolve this? Any keyword / operator I've forgotten about?
What you defined is not a function, it's just a value.
In order to define it as a function you can write this:
let private getDataSlowOperation() =
// implementation
UPDATE
To summarize the discussion:
This is the right way to write it as a function, however the code would still not work but that's a different problem.
The code would fail at runtime because () is compiled to null and by using a Dictionary you can't use null for the Key. You can use a Map instead.
John pointed out that memoization for functions without parameters makes no sense, I agree.
Still, if you use a Dictionary for functions with parameters you will run into the same problem with values that are compiled to null, ie: None
Updated below...
I recently started experimenting with ServiceStack in F#, so naturally I started with porting the Hello World sample:
open ServiceStack.ServiceHost
open ServiceStack.ServiceInterface
open ServiceStack.WebHost.Endpoints
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string }
[<CLIMutable>]
type HelloResponse = { Result : string }
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result = sprintf "Hello, %s!" req.Name }
type HelloAppHost() =
inherit AppHostBase("Hello Web Services", typeof<HelloService>.Assembly)
override x.Configure container = ()
type Global() =
inherit System.Web.HttpApplication()
member x.Application_Start() =
let appHost = new HelloAppHost()
appHost.Init()
That works great. It's very concise, easy to work with, I love it. However, I noticed that the routes defined in the sample allow for the Name parameter to not be included. Of course, Hello, ! looks kind of lame as output. I could use String.IsNullOrEmpty, but it is idiomatic in F# to be explicit about things that are optional by using the Option type. So I modified my Hello type accordingly to see what would happen:
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string option }
As soon as I did this, the F# type system forced me to deal with the fact that Name might not have a value, so I changed HelloService to this to get everything to compile:
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result =
match req.Name with
| Some name -> sprintf "Hello, %s!" name
| None -> "Hello!" }
This compiles, and runs perfectly when I don't supply a Name parameter. However, when I do supply a name...
KeyValueDataContractDeserializer: Error converting to type: Type
definitions should start with a '{', expecting serialized type
'FSharpOption`1', got string starting with: World
This wasn't a complete surprise of course, but it brings me to my question:
It would be trivial for me to write a function that can wrap an instance of type T into an instance of type FSharpOption<T>. Are there any hooks in ServiceStack that would let me provide such a function for use during deserialization? I looked, but I couldn't find any, and I'm hoping I was just looking in the wrong place.
This is more important for F# use than it might seem at first, because classes defined in F# are by default not allowed to be null. So the only (satisfying, non-hacky) way of having one class as an optional property of another class is with, you guessed it, the Option type.
Update:
I was able to sort-of get this working by making the following changes:
In the ServiceStack source, I made this type public:
ServiceStack.Text.Common.ParseFactoryDelegate
...and I also made this field public:
ServiceStack.Text.Jsv.JsvReader.ParseFnCache
With those two things public, I was able to write this code in F# to modify the ParseFnCache dictionary. I had to run this code prior to creating an instance of my AppHost - it didn't work if I ran it inside the AppHost's Configure method.
JsvReader.ParseFnCache.[typeof<Option<string>>] <-
ParseFactoryDelegate(fun () ->
ParseStringDelegate(fun s -> (if String.IsNullOrEmpty s then None else Some s) |> box))
This works for my original test case, but aside from the fact that I had to make brittle changes to the internals of ServiceStack, it sucks because I have to do it once for each type I want to be able to wrap in an Option<T>.
What would be better is if I could do this in a generic way. In C# terms, it would be awesome if I could provide to ServiceStack a Func<T, Option<T>> and ServiceStack would, when deserializing a property whose generic type definition matches that of the return type of my function, deserialize T and then pass the result into my function.
Something like that would be amazingly convenient, but I could live with the once-per-wrapped-type approach if it were actually part of ServiceStack and not my ugly hack that probably breaks something somewhere else.
So there are a couple of extensibility points in ServiceStack, on the framework level you can add your own Custom Request Binder this allows you to provide your own model binder that's used, e.g:
base.RequestBinders.Add(typeof(Hello), httpReq => {
var requestDto = ...;
return requestDto;
});
But then you would need to handle the model binding for the different Content-Types yourself, see CreateContentTypeRequest for how ServiceStack does it.
Then there are hooks at the JSON Serializer level, e.g:
JsConfig<Hello>.OnDeserializedFn = dto => newDto;
This lets you modify the instance of the type returned, but it still needs to be the same type but it looks like the F# option modifier changes the structural definition of the type?
But I'm open to adding any hooks that would make ServiceStack more palatable for F#.
What does the code look like to generically convert a normal Hello type to an F# Hello type with option?
The only thing I can think of is to replace the option type with your own type, one that has an implicit conversion from string to myOption, and anything else you need.
Not all that nice, but workable. Your type would probably also need to be serializable.
type myOption =
| None
| Some of string
static member public op_Implicit (s:string) = if s <> null then Some s else None
member public this.Value = match this with
| Some s -> s
| _ -> null
member this.Opt = match this with
| Some s -> Option.Some s
| None -> Option.None
Your record type would then be
[<CLIMutable>]
type Hello =
{ Name : myOption }
On the other hand, ServiceStack is open source, so maybe something could be done there.