I'm quite new at using F# and I'm trying to rewrite a full C# library in F#.I've have a Xamarin.forms project with a C# library containing all my Views and my goal is to have two others library, one in C# and one in F#, which each contains the same ViewModels.
All working fine except one last little thing with one of my property.
My application is simple, it just sign in a user to Facebook and then retrieve all the posts he puts on his Facebook Wall and display it using a ListView. While the retrieving work is processing, I want to Run an ActivityIndicator so the user can see that the App is working.
Here his my ActivityIndicator and my ListView in my view.xaml :
<ActivityIndicator IsVisible="{Binding IsLoading}" IsRunning="{Binding IsLoading}"
VerticalOptions="Center"
HorizontalOptions="Center"
Grid.Row="0"
Grid.Column="0"
Scale="4"
Color="#0078FF"/>
<ListView x:Name="PostsView"
ItemsSource="{Binding PostsDb}"
ItemTapped="PostsView_ItemTapped"
HasUnevenRows ="True"
BackgroundColor="LightGray"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"
Grid.Row="0"
Grid.Column="0"
IsVisible="{Binding IsLoading, Converter={StaticResource ReverseBool}}">
and here is my F# class :
type FacebookViewModel(navigationService: INavigationService) =
inherit ViewModelBase()
let mutable facebookProfile = new FacebookProfileDbObject()
let mutable postsDb = new List<FacebookPostsDbObject>()
let mutable isLoading = false
member this.FacebookProfile
with get() = facebookProfile
and set(value) =
facebookProfile <- value
base.NotifyPropertyChanged(<# this.FacebookProfile #>)
member this.PostsDb
with get() = postsDb
and set(value) =
postsDb <- value
base.NotifyPropertyChanged(<# this.PostsDb #>)
member this.IsLoading
with get() = isLoading
and set(value) =
isLoading <- value
base.NotifyPropertyChanged(<# this.IsLoading #>)
member this.SetData() =
this.IsLoading <- true
this.FacebookProfile <- GetProfileData() |> Async.RunSynchronously
this.PostsDb <- GetPostData() |> Async.RunSynchronously
this.IsLoading <- false
So I execute the SetData() Function in the OnAppearing() method in my View and my FacebookProfile and PostsDb data are well Bind to my ListView and it appears correctly.
The problem is that when it's passing through SetData(), my ActivityIndicator never appeared.
However, if I delete the this.IsLoading <- false line, it appears correctly (and never disappear obviously)
In My Debug Console I've no Binding Error and even in debug mode I see that my IsLoading property is well changed.
I just want to say that I know using F# this way is not really correct and produce ugly F# code, but it's just a test to use F# class.
I suspect that your issue is that these 4 lines are all being executed synchronously, and thus even though you this.IsLoading <- true correctly at the beginning, the UI never receives that message because your execution is essentially locked throughout the 4 lines:
this.IsLoading <- true
this.FacebookProfile <- GetProfileData() |> Async.RunSynchronously
this.PostsDb <- GetPostData() |> Async.RunSynchronously
this.IsLoading <- false
You need to find a way to run them asynchronously by first creating an asynchronous workflow:
async {
this.IsLoading <- true
let! profileData = GetProfileData()
let! postData = GetPostData()
this.FacebookProfile <- profileData
this.PostsDb <- postData
this.IsLoading <- false
}
Then decide how you're going to handle that workflow, if your code that calls GetData() can handle tasks you can pipe it to startAsTask:
member this.SetDataAsync() =
async {
// copy code from above
}
|> Async.startAsTask
Related
I don't yet understand why my addLink function does not get invoked.
I have the following code:
let links = source |> getLinks
let linkIds = links |> Seq.map addLink // addLink never gets executed
At first, I thought that the links value was empty.
However, it's not. I verified that it was populated by calling the following:
let count = Seq.length links // Returns over 100 items
Note:
The only way I have been able to execute the function is by first executing:
let count = linkIds |> Seq.length // Call this after performing map
Why do I need to do that just for my function to be called?
Appendix:
let addLink (info:Link) =
let commandFunc (command: SqlCommand) =
command |> addWithValue "#ProfileId" info.ProfileId
|> addWithValue "#Title" info.Title
|> addWithValue "#Description" info.Description
|> addWithValue "#Url" info.Url
|> addWithValue "#ContentTypeId" (info.ContentType |> contentTypeToId)
|> addWithValue "#IsFeatured" info.IsFeatured
|> addWithValue "#Created" DateTime.Now
commandFunc |> execute connectionString addLinkSql
[<CLIMutable>]
type Link = {
Id: int
ProfileId: string
Title: String
Description: String
Url: string
Topics: Topic list
ContentType: string
IsFeatured: bool
}
Here's the source code.
Seq<'a> is the same as IEnumerable<'a>, which is lazy. This means that each element in the sequence is only evaluated as it's needed. If you want to ensure that side-effects are called, then you could could convert this to a concrete data structure like list by adding Seq.toList.
However, it's better and usually possible to write code that performs side-effects separately to code that returns values. You could calculate the linkIds with one function and perform the side effects with another function using Seq.iter, which forces full evaluation of the sequence.
As an exercise I wanted to implement a 2-3 finger tree. That should be the perfect opportunity to try out FsCheck's model-based testing. I decided to try the newer experimental version.
So far I only coded one command for the test machine because I already fail at making that workâone the other hand it keeps the post short. The full code is available on GitHub.
open CmdQ
open Fuchu
open FsCheck
open FsCheck.Experimental
type TestType = uint16
type ModelType = ResizeArray<TestType>
type SutType = FingerTree<TestType>
let spec =
let prepend (what:TestType) =
{ new Operation<SutType, ModelType>() with
override __.Run model =
// Also tried returning the same instance.
let copy = model |> ResizeArray
copy.Insert(0, what)
copy
override __.Check(sut, model) =
let sutList = sut |> Finger.toList
let newSut = sut |> Finger.prepend what
let newSutList = newSut |> Finger.toList
let modelList = model |> Seq.toList
let areEqual = newSutList = modelList
areEqual |# sprintf "prepend: model = %A, actual = %A (incoming was %A)" modelList newSutList sutList
override __.ToString() = sprintf "prepend %A" what
}
let create (initial:ModelType) =
{ new Setup<SutType, ModelType>() with
override __.Actual () = initial |> Finger.ofSeq
override __.Model () = initial //|> ResizeArray // Also tried this.
}
let rndNum () : Gen<TestType> = Arb.from<uint16> |> Arb.toGen
{ new Machine<SutType, ModelType>() with
override __.Setup =
rndNum()
|> Gen.listOf
|> Gen.map ResizeArray
|> Gen.map create
|> Arb.fromGen
override __.Next _ = gen {
let! cmd = Gen.elements [prepend]
let! num = rndNum()
return cmd num
}
}
[<Tests>]
let test =
[spec]
|> List.map (StateMachine.toProperty >> testProperty "Finger tree")
|> testList "Model tests"
What I understand is this: Operation<_>.Run is run twice to build up a ResizeArray from one with a single element. Then Operation<_>.Check is run twice with the same numbers to insert into a single element FingerTree<_>.
The first of the two passes. Single-element tree incoming, adding makes it a (correct) two-element tree which compares well against the model after the first command.
The second command is always the one failing. Check is called with the bigger ResizeList (now 3 elements) but the same single-element Tree as in the first command. Adding one more element of course does not get it to size 3 and the test fails.
I would have expected that I need to return the updated model from Check for the commands to come. But you need to return a Property so that's not possible.
Did I completely misunderstand how to approach this? How should a working model-based test be written?
The model-based testing assumes that the "system under test" is modified as a side-effect when Check is called on a particular operation, and initialized for that test run when Setup.Actual() is called. It is intended for dealing with systems that are mutable - like a mutable object - and that style while somewhat bewildering here works out quite nicely with such systems.
Since your finger tree type is immutable, my advice would be to redefine SutType to:
type SutType = Ref<FingerTree<TestType>>
and modify the rest accordingly.
I am new to functional programming in general and started learning F# recently. I wanted to use an async workflow returning Async<'U option> to pick an item in a Sequence. I find a nice Seq.pick function, but I am not sure how I could use that with an async workflow.
If that is not possible, is there another alternative to using an imperative style program to pick the item from the list. The following is a modified variation of my program. Any feedback is highly appreciated.
let run = async {
while not stopped do
use! resource = acquireResourceLockAsync
let! items = fetchItemsAsync 5
let! item = Seq.pick returnIfLocked items
let! status = performTaskAsync item
do! updateStatusAsync status
do! Async.Sleep 1000
}
Thanks in anticipation.
EDIT: Updated my question based on the answer by jpalmer. I noticed both Seq.filter and Seq.pick earlier and decided that Seq.pick will meet my need better, as I need the first item that I am able to lock. However, I forgot to change the return value of my function - instead of returning true, it should return Some(item). Now with that update, is there an elegant way to approach this without 1) blocking a thread to convert Async<'U option> to 'U and 2) resorting to an imperative style looping?
I am unclear exactly what you are trying to do. If you want to convert from Async<'T> to 'T non-blocking, then you want to use let! in an async workflow. So the seq-like logic probably needs to be written as its own loop, as suggested below. If that doesn't help, then perhaps share more code, especially the intended types of items/item/returnIfLocked, as I'm unclear what's async in your example.
let asyncPick f (s:seq<_>) =
async {
use e = s.GetEnumerator()
let r = ref None
while Option.isNone(!r) && e.MoveNext() do
let! x = f e.Current
r := x
match !r with
| Some z -> return z
| None -> return failwith "no matching item found"
}
let chooser ax =
async {
let! x = ax
if x%3 = 0 then
return Some x
else
return None
}
let s = seq { for i in 1..10 do yield async { return i } }
let main() =
async {
let! firstChosen = s |> asyncPick chooser
return firstChosen
}
|> Async.RunSynchronously
|> printfn "%d"
main()
It is important to look at the signature of the function you are using,
Seq.pick expects a function which returns option<'t>, you want to use Seq.Filter which takes a function which returns a bool.
You will still have another problem though in that you have Async<bool> - you will need to convert that to a normal bool, but you could do this inside your 'Seq.Filter' function
I wrote the following function to view data in a grid from F# interactive:
open System.Windows.Forms
let grid x =
let form = new Form(Visible = true)
let data = new DataGridView(Dock = DockStyle.Fill)
form.Controls.Add(data)
data.DataSource <- x |> Seq.toArray
How can I make it work for both 1D and 2D seqs? say, grid [1,2,3] or grid[(1,0);(2,0);(3,0)];; works fine but grid [1;2;3];; would not work.
another question is, why do I have to add the `|>Seq.toArray to make it work?
DataGridView uses databinding that reflects over object properties and displays them in grid columns (possibly automatically inferred). [1,2,3] and [(1,0);(2,0);(3,0)] are lists of tuples so DataGridView can show tuple components, As opposite, [1;2;3] - list of integers, it doesn't contains any properties that exposes the actual value.
Seq.ToArray is necessary because DataSource expects IList, IListSource, IBindingList or IBindingListView (DataGridView.DataSource Property ). Array implements IList, F# list - doesn't.
As desco explains, the DataGridView control displays values of properties of the object.
This is pretty silly behavior for primitive types - for example if you specify [ "Hello"; "world!" ] as the data source, it will display column Length with values 5 and 6. That's definitely not what you'd want!
The best solution I could find is to explicitly check for strings and primitive types and wrap them in a simple type with just a single property (that will get displayed):
type Wrapper(s:obj) =
member x.Value = s.ToString()
let grid<'T> (x:seq<'T>) =
let form = new Form(Visible = true)
let data = new DataGridView(Dock = DockStyle.Fill)
form.Controls.Add(data)
data.AutoGenerateColumns <- true
if typeof<'T>.IsPrimitive || typeof<'T> = typeof<string> then
data.DataSource <- [| for v in x -> Wrapper(box v) |]
else
data.DataSource <- x |> Seq.toArray
grid [ 1 .. 10 ]
grid [ "Hello"; "World" ]
I just finish writing my first F# program. Functionality wise the code works the way I wanted, but not sure if the code is efficient. I would much appreciate if someone could review the code for me and point out the areas where the code can be improved.
Thanks
Sudaly
open System
open System.IO
open System.IO.Pipes
open System.Text
open System.Collections.Generic
open System.Runtime.Serialization
[<DataContract>]
type Quote = {
[<field: DataMember(Name="securityIdentifier") >]
RicCode:string
[<field: DataMember(Name="madeOn") >]
MadeOn:DateTime
[<field: DataMember(Name="closePrice") >]
Price:float
}
let m_cache = new Dictionary<string, Quote>()
let ParseQuoteString (quoteString:string) =
let data = Encoding.Unicode.GetBytes(quoteString)
let stream = new MemoryStream()
stream.Write(data, 0, data.Length);
stream.Position <- 0L
let ser = Json.DataContractJsonSerializer(typeof<Quote array>)
let results:Quote array = ser.ReadObject(stream) :?> Quote array
results
let RefreshCache quoteList =
m_cache.Clear()
quoteList |> Array.iter(fun result->m_cache.Add(result.RicCode, result))
let EstablishConnection() =
let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
let mutable sr = null
printfn "[F#] NamedPipeServerStream thread created, Wait for a client to connect"
pipeServer.WaitForConnection()
printfn "[F#] Client connected."
try
// Stream for the request.
sr <- new StreamReader(pipeServer)
with
| _ as e -> printfn "[F#]ERROR: %s" e.Message
sr
while true do
let sr = EstablishConnection()
// Read request from the stream.
printfn "[F#] Ready to Receive data"
sr.ReadLine()
|> ParseQuoteString
|> RefreshCache
printfn "[F#]Quot Size, %d" m_cache.Count
let quot = m_cache.["MSFT.OQ"]
printfn "[F#]RIC: %s" quot.RicCode
printfn "[F#]MadeOn: %s" (String.Format("{0:T}",quot.MadeOn))
printfn "[F#]Price: %f" quot.Price
In general, you should try using immutable data types and avoid imperative constructs such as global variables and imperative loops - although using them in F# is fine in many cases, they should be used only when there is a good reason for doing so. Here are a couple of examples where you could use functional approach:
First of all, to make the code more functional, you should avoid using global mutable cache. Instead, your RefreshCache function should return the data as the result (preferably using some functional data structure, such as F# Map type):
let PopulateCache quoteList =
quoteList
// Generate a sequence of tuples containing key and value
|> Seq.map (fun result -> result.RicCode, result)
// Turn the sequence into an F# immutable map (replacement for hashtable)
|> Map.ofSeq
The code that uses it would be changed like this:
let cache =
sr.ReadLine()
|> ParseQuoteString
|> PopulateCache
printfn "[F#]Quot Size, %d" m_cache.Count
let quot = m_cache.["MSFT.OQ"]
// The rest of the sample stays the same
In the EstablishConnection function, you definitely don't need to declare a mutable variable sr, because in case of an exception, the function will return null. I would instead use option type to make sure that this case is handled:
let EstablishConnection() =
let pipeServer =
new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
printfn "[F#] NamedPipeServerStream thread created..."
pipeServer.WaitForConnection()
printfn "[F#] Client connected."
try // Wrap the result in 'Some' to denote success
Some(new StreamReader(pipeServer))
with e ->
printfn "[F#]ERROR: %s" e.Message
// Return 'None' to denote a failure
None
The main loop can be written using a recursive function that stops when EstablishConnection fails:
let rec loop() =
match EstablishConnection() with
| Some(conn) ->
printfn "[F#] Ready to Receive data"
// rest of the code
loop() // continue looping
| _ -> () // Quit
Just a couple thoughts...
You probably want a 'use' rather than a 'let' in a few places, as I think some of the objects in the program are IDisposable.
You may consider wrapping the EstablishConnection method and the final while loop in async blocks (and make other minor changes), so that e.g. you can wait asynchronously for connections without blocking a thread.
At first glance it is written in imperative style rather than functional style, which does make sense given that most of the program involves side effects (i.e. I/O). Line for line, it almost looks like a C# program.
Given the amount of I/O that is taking place, I don't know that there is much you can do to this particular program to make it more of a functional style of coding.