I have the following .fsx script:
#r "packages/FSharp.Data/lib/net40/FSharp.Data.dll"
open FSharp.Data
async { let! html = Http.AsyncRequestString("http://stackoverflow.com")
printfn "%d" html.Length }
|> Async.Start
The code is correct, since it works as expected in fsharpi. I suspect what's happening is that the script exits before the async response is back. What's the easiest way to wait for the response to be back?
You can use |> Async.RunSynchronously in this case. Please see https://msdn.microsoft.com/en-us/library/dd233250.aspx or Chapter 11 in the Expert F# 4.0 book. Async.Start can be very useful kicking of functions that will return their results to the GUI without blocking.
Related
I have a fairly simple use case:
Start a process serving an AspNetCore app with Swagger middleware for generating a swagger.json file.
Start a process that reads said swagger.json and generates a C# REST client
Wait until the C# Rest client has been generated and then shut down the AspNetCore app.
Currently my code looks like this:
try
let createProc =
CreateProcess.fromRawCommand "dotnet" ["run"; "--project"; "FakeProcMvc"]
|> CreateProcess.addOnStarted
(fun _ ->
CreateProcess.fromRawCommand "dotnet" ["run"; "--project"; "FakeProcWriteFile"]
|> Proc.run
|> ignore
)
let procTask =
createProc
|> Proc.start
let tokenSource = new CancellationTokenSource()
procTask.Wait(tokenSource.Token)
tokenSource.Cancel()
with
| Failure msg -> printfn "caught: %A" msg
But this is clearly not quite right. The file writing (C# client) works fine, but I can't get the AspNetCore app to stop.
The canceling part does nothing, and I don't know how to get some kind of reference to the actual process so I can use Process.kill or similar.
I have written a F# script in FSI using Ionide in VS Code. It's a great tool, but I am getting a warning from Ionide Lint suggesting a code improvement:
'Lint: Seq.map f (Seq.map g x) might be able to be refactored into Seq.map (g >> f) x.'
I have about 6 Seq.map functions all piped together with |> which I am happy with.
There is also a green wiggly line that is annoying me. I don't agree with the suggestion, and want the wiggly line to go away. How can I tell Ionide to stop making this suggestion?
I have turned off Lint globally in the VS Code settings
"FSharp.linter": false,
I think Ionide uses FsharpLint: http://fsprojects.github.io/FSharpLint/
This supports suppressing of lint messages like this:
[<SuppressMessage("NameConventions", "InterfaceNamesMustBeginWithI")>]
type Printable =
abstract member Print : unit -> unit
Something like that might work for you as well. I just turned it off.
This is the directive to disable this particular message in code:
open System.Diagnostics.CodeAnalysis
[<SuppressMessage("Hints", "") >]
Place above the block that is producing this 'error'.
I have something like :-
pathScan "/blah/%s" (fun x) -> (sprintf "%A" x) |> json)
and what it shows me if I do /blah/AT%2BVER%3F is the url encoded data. Is there a way to get this decoded automatically? or do I need to parse all my parameters ( which seems a bit odd )
Some older versions require manually decoding. Note that a pull request was accepted (and is now in the current release) which should address this in the next release.
Currently, the best option is to either upgrade to the latest Suave or run this through System.Web.HttpUtility.UrlDecode yourself (as this is the mechanism being used by Suave vCurrent).
I'm trying to use the following F# code to access a Xaml control.
let (?) (source:obj) (s:string) =
match source with
| :? ResourceDictionary as r -> r.[s] :?> 'T
| :? Control as source ->
match source.FindName(s) with
| null -> invalidOp (sprintf "dynamic lookup of Xaml component %s failed" s)
| :? 'T as x -> x
| _ -> invalidOp (sprintf "dynamic lookup of Xaml component %s failed because the component found was of type %A instead of type %A" s (s.GetType()) typeof<'T>)
| _ -> invalidOp (sprintf "dynamic lookup of Xaml component %s failed because the source object was of type %A. It must be a control or a resource dictionary" s (source.GetType()))
This is from Daniel Mohl's excellent F# for Windows Phone template.
I've created a class to basically read the accelerometer and trigger an event when the phone is shaken. The event gets raised as expected but for some reason it's spawned in a second thread--which leads the CLR to throw an "invalid cross-thread access" exception when the event handler attempts to execute this code. The exception is thrown on the source.FindName(s) call. I can see a second thread of execution--which kind of surprises me because I didn't specifically spawn a secondary thread. I mean I didn't explicitly call async or do anything else that I can think of that would cause a secondary thread of execution to start.
So it seems like there are a few approaches I could take:
I could try to figure out why I'm
spawning a secondary thread when I
haven't specifically requested it and modify the code to prevent a secondary thread of
execution from being spawned.
I could try to modify the (?)
function to account for multiple
threads of execution but I'd really
like to understand why I'm getting a
second thread started
I think probably the second approach is best but I'd really like to understand what I'm doing that's causing a secondary thread to spawn. I realize how hard that is to answer without specific code but I don't mind researching this if someone can point me in the right direction. I believe this has something to do with the Windows 7 Phone platform because the code is, as far as I can tell, pretty much the idiomatic way to bind a Xaml control with F# code.
Any thoughts, comments, suggestions would be greatly appreciated.
Cross-posted to HubFS as well
Event handling in WP7 is generally handled on async callbacks. Accessing the accelerometer is no exception.
You'll need to direct any code that results in a UI update to the dispatcher.
In c# this can be done like
Dispatcher.BeginInvoke( () => { /* your UI code */ } );
The approach for sending results to the Dispatcher used in this post may also be helpful for you in f# as it's more of a functional style than imperative as a result of using Rx.
WP7 Code: Using the Accelerometer API - Dragos Manolescu's (work) blog
How do you use Console.Readline in F#? Unlike Console.Writeline, it isn't being honored when I call it.
If you use
let s = Console.ReadLine
you are only building a delegate that points to the ReadLine function. You need to say
let s = Console.ReadLine()
to actually execute the function. This is just like C# syntax, except type inference means you don't get a compiler warning.
What do you mean by "it isn't being honored"? Here's a small console app I've just written in VS2010b1, and it works fine:
open System
let line = Console.ReadLine()
Console.WriteLine("You wrote {0}", line)
// Just to make it pause
let unused = Console.ReadLine()
Are you trying to run the code from F# Interactive within Visual Studio? If so, that may be the issue, as Brian's post explains.
However, I haven't seen the same problem when using F# Interactive from the command line. Here's a complete transcript of a session:
Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.16, compiling for .NET Framework Version v4.0.20506
Please send bug reports to fsbugs#microsoft.com
For help type #help;;
> open System;;
> let line = Console.ReadLine();;
Hello world
val line : string = "Hello world"
Running Brian's looping code from F# Interactive didn't show the same problem.
Bottom line: It seems like this is broken in F# Interactive in Visual Studio, but not when running interactively from the command line or in a full console app.
I don't have a Beta1 box handy, but I know that in the past we've had a bug where ReadLine() would see the background commands that communicate between the interactive UI and the background process that runs your F# code. It may be interesting to investigate what
let Foo max =
let rec Loop i =
if i < max then
let line = System.Console.ReadLine()
printfn "line = %s" line
Loop (i+1)
Loop 1
Foo 12
prints when you highlight it and 'Send to Interactive'. I think possibly you'll see a few unexpected interesting lines, followed by lines you type into the window.
// is the right way if you're not wanting to use a return of anything typed into readline
Console.ReadLine() |> ignore