Unexpected keyword error in simple F# code - f#

I'm creating a tiny function that will generate an alphanumeric string randomly like so
open System
let randomStr (len : int) : string =
let rand = new Random()
let ch = Array.concat [| [|'a' .. 'z'|];[|'A' .. 'Z'|];[|'0' .. '9'|] |]
let sz = Array.length ch in
System.String(Array.init len (fun _ -> ch.[rand.Next sz]))
let e = randomStr 5
printf "%s" e
I seem to keep receiving the following error and I have no clue as to why
error FS0010: Unexpected keyword 'let' or 'use' in expression. Expected 'in' or other token.

I suspect you have lightweight syntax turned off via #light "off". I've reproduced the same error outside of Visual Studio here. Try removing the #light directive. There might also be some setting in VS2017 that disables lightweight syntax, but I don't have a copy handy that I can try. Lightweight syntax is now considered the norm in F#, so there's rarely any need for the old verbose style.

Related

Slow conversion of F# discriminated union case to string

I have around 100k discriminated union cases I have to convert to strings, but it seems to be extremely slow.
As a comparison, the following executes (in F# interactive) in 3seconds on average :
open System
let buf = Text.StringBuilder()
let s = DateTime.Now
for i in 1 .. 100000 do
Printf.bprintf buf "%A" "OtherFinancingInterest" //string
buf.Length <- 0
printfn "elapsed : %0.2f" (DateTime.Now - s).TotalMilliseconds
While the following executes (also in F# interactive) in over a minute...
open System
let buf = Text.StringBuilder()
let s = DateTime.Now
for i in 1 .. 100000 do
Printf.bprintf buf "%A" OtherFinancingInterest //DU
buf.Length <- 0
printfn "elapsed : %0.2f" (DateTime.Now - s).TotalMilliseconds
The discriminated union has 25 values (the result is still extremely slow, around 16 seconds with two cases, but less so than with 25). Any idea if that is "normal" or if I may be doing something wrong ?
Many thanks
The %A format specifier pretty prints any F# value. It uses reflection to do so. It should only really be used for debugging purposes, and not in normal application code.
Note that using %s in your first example using a string makes it a lot faster because there is no type checking needed at runtime.
For the DU, there is a hack you could use to make the reflection only happen once on application load:
type FinancingInterest =
| OtherFinancingInterest
open FSharp.Reflection
let private OtherFinancingInterestStringMap =
FSharpType.GetUnionCases typeof<FinancingInterest>
|> Array.map (fun c -> FSharpValue.MakeUnion(c, [||]) :?> FinancingInterest)
|> Array.map (fun x -> x, sprintf "%A" x)
|> Map.ofArray
type FinancingInterest with
member this.AsString = OtherFinancingInterestStringMap |> Map.find this
You would also use this with the %s format specifier:
Printf.bprintf buf "%s" OtherFinancingInterest.AsString
I had similar timings to yours in your example, and now this one comes down to 40ms.
This only works as long as all of the DU cases don't have an arguments. You will get an exception on application load as soon as you try anything like this:
type FinancingInterest =
| Foo of string
| OtherFinancingInterest
Having said all this, I think you're better off writing a simple function that explicitly converts your type into a string value, writing out the names in full with repetition if necessary. The names of discriminated union cases should not generally be thought of as data that affects your program. You would usually expect to be able to safely rename case names without affecting runtime behaviour at all.

Custom FsCheck Arbitrary type broken in Xunit but working in LINQPad and regular F# program

I'm trying to implement a custom Arbitrary that generates glob syntax patterns like a*c?. I think my implementation is correct, it's just that, when running the test with Xunit, FsCheck doesn't seem to be using the custom arbitrary Pattern to generate the test data. When I use LINQPad however everything works as expected. Here's the code:
open Xunit
open FsCheck
type Pattern = Pattern of string with
static member op_Explicit(Pattern s) = s
type MyArbitraries =
static member Pattern() =
(['a'..'c']#['?'; '*'])
|> Gen.elements
|> Gen.nonEmptyListOf
|> Gen.map (List.map string >> List.fold (+) "")
|> Arb.fromGen
|> Arb.convert Pattern string
Arb.register<MyArbitraries>() |> ignore
[<Fact>]
let test () =
let prop (Pattern p) = p.Length = 0
Check.QuickThrowOnFailure prop
This is the output:
Falsifiable, after 2 tests (0 shrinks) (StdGen (1884571966,296370531)): Original: Pattern null with exception: System.NullReferenceException ...
And here is the code I'm running in LINQPad along with the output:
open FsCheck
type Pattern = Pattern of string with
static member op_Explicit(Pattern s) = s
type MyArbitraries =
static member Pattern() =
(['a'..'c']#['?'; '*'])
|> Gen.elements
|> Gen.nonEmptyListOf
|> Gen.map (List.map string >> List.fold (+) "")
|> Arb.fromGen
|> Arb.convert Pattern string
Arb.register<MyArbitraries>() |> ignore
let prop (Pattern p) = p.Length = 0
Check.Quick prop
Falsifiable, after 1 test (0 shrinks) (StdGen (1148389153,296370531)): Original: Pattern "a*"
As you can see FsCheck generates a null value for the Pattern in the Xunit test although I'm using Gen.elements and Gen.nonEmptyListOf to control the test data. Also, when I run it a couple times, I'm seeing test patterns that are out of the specified character range. In LINQPad those patterns are generated correctly. I also tested the same with a regular F# console application in Visual Studio 2017 and there the custom Arbitrary works as expected as well.
What is going wrong? Is FsCheck falling back to the default string Arbitrary when running in Xunit?
You can clone this repo to see for yourself: https://github.com/bert2/GlobMatcher
(I don't want to use Prop.forAll, because each test will have multiple custom Arbitrarys and Prop.forAll doesn't go well with that. As far as I know I can only tuple them up, because the F# version of Prop.forAll only accepts a single Arbitrary.)
Don't use Arb.register. This method mutates global state, and due to the built-in parallelism support in xUnit.net 2, it's undetermined when it runs.
If you don't want to use the FsCheck.Xunit Glue Library, you can use Prop.forAll, which works like this:
[<Fact>]
let test () =
let prop (Pattern p) = p.Length = 0
Check.QuickThrowOnFailure (Prop.forAll (MyArbitraries.Pattern()) prop)
(I'm writing this partially from memory, so I may have made some small syntax mistakes, but hopefully, this should give you an idea on how to proceed.)
If, on the other hand, you choose to use FsCheck.Xunit, you can register your custom Arbitraries in a Property annotation, like this:
[<Property(Arbitrary = [|typeof<MyArbitraries>|])>]
let test (Pattern p) = p.Length = 0
As you can see, this takes care of much of the boilerplate; you don't even have to call Check.QuickThrowOnFailure.
The Arbitrary property takes an array of types, so when you have more than one, this still works.
If you need to write many properties with the same array of Arbitraries, you can create your own custom attributes that derives from the [<Property>] attribute. Here's an example:
type Letters =
static member Char() =
Arb.Default.Char()
|> Arb.filter (fun c -> 'A' <= c && c <= 'Z')
type DiamondPropertyAttribute() =
inherit PropertyAttribute(
Arbitrary = [| typeof<Letters> |],
QuietOnSuccess = true)
[<DiamondProperty>]
let ``Diamond is non-empty`` (letter : char) =
let actual = Diamond.make letter
not (String.IsNullOrWhiteSpace actual)
All that said, I'm not too fond of 'registering' Arbitraries like this. I much prefer using the combinator library, because it's type-safe, which this whole type-based mechanism isn't.

F# Seq.choose() Error FS0001

I have tried MSDN's example for the Seq.choose function (written below) in both a .fsx file and the interactive window for Visual Studio, but it repeatedly returns an error FS0001, stating that the "None" option is a PageExt type rather than the abstract option type 'a option.
I have searched in vain for an explanation of the PageExt type or why this could be returning an error when the None keyword should just represent the "no value" option in the match expression.
let numbers = seq {1..20}
let evens = Seq.choose(fun x ->
match x with
| x when x%2=0 -> Some(x)
| _ -> None ) numbers
printfn "numbers = %A\n" numbers
printfn "evens = %A" evens
;;
| _ -> None ) numbers
---------------------------------------^^^^
>
C:Path\stdin(38,40): error FS0001: This expression was expected to have type
'a option
but here has type
PageExt
Thanks for any help anyone can offer!
The PageExt type is likely something that you've pulled into your current FSI session previously which bound something to None, essentially blocking FSI from recognizing the normal option types.
In F#, you can reuse names, which "shadows" the original value. For example, in FSI, if you type:
let a = 1;;
let a = 2.3;;
a;;
You'll notice that it shows:
val a : int = 1
Then
val a : float = 2.3
Finally
val it : float = 2.3
This isn't changing the definition of a, but rather defining a new a name that shadows (or "hides") the original bound value.
In your case, you have a None name that's bound to something with a PageExt type that's shadowing Option.None, preventing it from being usable.
The easiest way to fix this is to reset your FSI session. Right click in the F# Interactive window, and choose "Reset iteractive session". If you do that, then run the code you pasted, it will work fine.

How to compose F# Active Pattern Matching functions inside a Function Expression?

We have this small helper functions
open System
let (|NonEmptyString|) value =
if String.IsNullOrEmpty value
then failwith "String must be non-empty."
else value
let (|StartsWithX|) (value:string) =
if value.StartsWith("X") |> not
then failwith "String must start with X."
else value
And using the active pattern matching function NonEmptyString in the function interface works fine:
let hi (NonEmptyString s) = printfn "Hi %s" s
hi "X" // Hi X
hi "" // System.Exception: String must be non-empty.
Now to the problem.
It would be nice to combine some validators together as a more complex validation constraint, like so
let hi (NonEmptyString s & StartsWithX s) = printfn "Hi %s" s
// error FS0038: 's' is bound twice in this pattern
If only one 's' is allowed, we can think of combining the functions so we have only one argument s.
And because active pattern matching functions are functions of course, applying the function composition operator >> but it does not fit here.
let hi (NonEmptyString >> StartsWithX s) = printfn "Hi %s" s
// error FS0010: Unexpected infix operator in pattern
The question is, how can we do that (in F# 4.0) ?
As #kvb commented, the wildcard _ helps in the AND case
// AND
let hi (NonEmptyString _ & StartsWithX s) = printfn "Hi %s" s
The OR case works with with two 's' bindings
// OR
let hi (NonEmptyString s | StartsWithX s) = printfn "Hi %s" s
// The logic here makes less sense. It's kept simple with the given helper functions from above.
Note:
This is just for experimenting with composition of Active Pattern Matching as code contracts in a descriptive way at the function interface.
This can be seen as use or misuse of Active Pattern Matching (idiomatic F# or not), it's your choice!

F#: warning FS0020: This expression should have type 'unit', but has type 'bool'

I'm trying to learn F# by going through some of the Euler problems and I found an issue I haven't been able to figure out. This is my naive solution.
let compute =
let mutable f = false
let mutable nr = 0
while f = false do
nr <- nr + 20
f = checkMod nr
nr
When i do this I get the error message warning FS0020: This expression should have type 'unit', but has type 'bool' on the expression "nr <- nr +20". I've tried rewriting and moving the expressions around and I always get that error on the line below the while statement.
I'm writing this using VS2010 Beta.
Since I can imagine this weg page becoming the 'canonical' place to look up information about warning FS0020, here's my quick summary of the three commonest cases in which you get the warning, and how to fix them.
Intentionally discarding the result of a function that is called only for its side-effects:
// you are calling a function for its side-effects, intend to ignore result
let Example1Orig() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") // warning FS0020
sb.Append(" there") // warning FS0020
sb.ToString()
let Example1Fixed() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") |> ignore
sb.Append(" there") |> ignore
sb.ToString()
Warning is useful, pointing out an error (function has no effects):
// the warning is telling you useful info
// (e.g. function does not have an effect, rather returns a value)
let Example2Orig() =
let l = [1;2;3]
List.map (fun x -> x * 2) l // warning FS0020
printfn "doubled list is %A" l
let Example2Fixed() =
let l = [1;2;3]
let result = List.map (fun x -> x * 2) l
printfn "doubled list is %A" result
Confusing assignment operator and equality comparison operator:
// '=' versus '<-'
let Example3Orig() =
let mutable x = 3
x = x + 1 // warning FS0020
printfn "%d" x
let Example3Fixed() =
let mutable x = 3
x <- x + 1
printfn "%d" x
The following line:
f = checkMod nr
is an equality check, not an assignment as I believe you are intending. Change it to:
f <- checkMod nr
and all should work fine. I'm not sure why you've used the correct syntax on the previous line and not that line...
Also, the line while f = false do should really be simplified to while not f do; equality checks on booleans are rather convoluted.
As I side note, I feel a need to point out that you are effectively trying to use F# as an imperative language. Use of mutable variables and while loops are strongly discouraged in functional languages (including F#), especially when a purely functional (and simpler) solution exists, as in this situation. I recommend you read up a bit on programming in the functional style. Of course, just getting to grips with the syntax is a useful thing in itself.
If you're trying to adopt the functional style, try to avoid mutable values.
For example like this:
let nr =
let rec compute nr =
if checkMod nr then nr else compute (nr + 20)
compute 0
while expressions in F# take a little getting used to if you're coming from an imperative language. Each line in a while expression must evaluate to unit (think void from C++/C#). The overall expression then also evaluates to unit.
In the example:
nr <- nr + 20
evaluates to unit whereas
f = checkMod nr
evaluates to a bool as Noldorin noted. This results in a warning message being reported. You can actually turn the warning off if you so desire. Just put the following at the top of your file:
#nowarn "0020"
I've been programming in an imperative style for a long time, so getting used to the functional programming mindset took a while.
In your example, you're trying to find the first multiple of 20 that passes your checkMod test. That's the what part. For the functional how part, I recommend browsing through the methods available to sequences. What you need is the first element of a sequence (multiples of 20) passing your test, like this:
let multi20 = Seq.initInfinite (fun i -> i*20)
let compute = multi20 |> Seq.find checkMod
The first let generates an infinite list of twentyples (I made that one up). The second let finds the first number in said list that passes your test. Your task is to make sure that there actually is a number that will pass the test, but that's of course also true for the imperative code.
If you want to condense the two above lines into one, you can also write
let computeCryptic = Seq.initInfinite ((*) 20) |> Seq.find checkMod
but I find that pulling stunts like that in code can lead to headaches when trying to read it a few weeks later.
In the same spirit as Brian's post, here is another way to get warning FS0020: In a nutshell, I accidentally tupled the function arguments.
Being an F# newbie, I had a difficult time debugging the code below, which for the second line (let gdp...) gave the warning FS0020: This expression should have type 'unit', but has type '(string -> ^a -> unit) * string * float'. It turns out that line was not the problem at all; instead, it was the printfn line that was messed up. Removing the comma separators from the argument list fixed it.
for country in wb.Regions.``Arab World``.Countries do
let gdp = country.Indicators.``GDP per capita (current US$)``.[2010]
let gdpThous = gdp / 1.0e3
printfn "%s, %s (%.2f)" country.Name, country.CapitalCity, gdpThous

Resources