When I run this FsUnit test with NUnit 2.6.3,
let f xs = Some (List.map ((+) 2) xs)
[<Test>]
let test() =
f []
|> should equal (Some [])
I get:
Result Message:
Expected: <Some([])>
But was: <Some([])>
Result StackTrace:
at FsUnit.TopLevelOperators.should[a,a](FSharpFunc`2 f, a x, Object y)
The test fails even though the Expected and Actual in the message are the same. What happened?
The reason is that FsUnit uses untyped mechanism under the hood so Expected is inferred as object by the type checker (see the Object y part in the stacktrace).
A workaround is to add type annotation for generic values i.e.
[<Test>]
let test() =
f []
|> should equal (Some ([]: int list))
Several people have been bitten by this e.g. Weird None behaviour in type providers.
Beauty of fluent assertions is pointless to me once they're no longer type-safe. I suggest to create a type-safe alternative:
let shouldEqual (x: 'a) (y: 'a) =
Assert.AreEqual(x, y, sprintf "Expected: %A\nActual: %A" x y)
This is because your two empty lists are of different types. See the types of actual and expected in this version of your test:
[<Test>]
let test() =
let expected = Some []
let actual = f []
actual |> should equal expected
expected is 'a list option and actual is int list option, so they are not equal.
If you give the compiler some hints about the expected result then it will work.
[<Test>]
let test() =
f []
|> should equal (Some List.empty<int>)
Related
I was experimenting with an implementation of Clojure Transducers in F#, and quickly hit the dreaded Value Restriction error.
The whole point of Transducers is to be composable. This is some sample code:
type Reducer<'a,'b,'c> = ('a -> 'b -> 'a) -> 'a -> 'c -> 'a
module Transducers =
[<GeneralizableValue>]
let inline map proj : Reducer<'result,'output,'input> =
fun xf ->
fun result input ->
xf result (proj input)
let inline conj xs x = x :: xs
let inline toList xf input = List.fold (xf conj) [] input
let xform = map (fun i -> i + 9) >> map (fun a -> a * 5)
//let xs = toList xform [1;2] // if you apply this, type will be fixed to 'a list
// which makes xform unusable with eg 'a seq
Play on dotnetfiddle
GeneralizableValue was supposed to lift the value restriction, but does nothing, it seems. Your mission is to make this code compile without applying toList (Type inference will fix the type to 'a list, so you could not use the same xform with a seq) and without changing the type of xform (at least not in a way so as to make it not composable). Is this simply not possible in F#?
Why would annotating map with [<GeneralizableValue>] affect whether xform is subject to the value restriction? (in any case, map is already generalizable since it's defined by a lambda; also I don't see the point of all the inlines).
If your requirements are:
xform must be generic, but not an explicitly annotated type function
xform is defined by the application of an operator ((>>) in this case)
then you're out of luck; xform's body is not a generalizable expression (see ยง14.7 in the F# spec), so the value restriction applies here.
Furthermore, I would argue that this makes sense. Imagine that the value restriction didn't apply, and that we tweaked the definition of map:
let map proj : Reducer<_,_,_> =
printfn "Map called!"
fun xf result input ->
xf result (proj input)
Now enter these definitions one-by-one:
let xform<'a> : Reducer<'a,int,int> = map (fun i -> i + 9) >> map (fun a -> a * 5)
let x1 = xform (+)
let x2 = xform (*)
let x3 = xform (fun s i -> String.replicate i s)
When do you expect "Map called!" to be printed? Does the actual behavior match your expectations? In my opinion it's good that F# forces you to go out of your way to treat non-values as generic values.
So you're not going to get exactly what you want. But perhaps there's a different encoding that would work just as well for your use cases. If every reducer will be generic in the result type, then you could do this instead:
type Reducer<'b,'c> = abstract Reduce<'a> : ('a -> 'b -> 'a) -> 'a -> 'c -> 'a
module Transducers =
let map proj =
{ new Reducer<_,_> with
member this.Reduce xf result input = xf result (proj input) }
let (>!>) (r1:Reducer<'b,'c>) (r2:Reducer<'c,'d>) =
{ new Reducer<_,_> with
member this.Reduce xf result input = (r1.Reduce >> r2.Reduce) xf result input }
let conj xs x = x :: xs
let toList (xf:Reducer<_,_>) input = List.fold (xf.Reduce conj) [] input
let xform = map (fun i -> i + 9) >!> map (fun a -> a * 5)
Unfortunately, you've got to lift each operator like (>>) to the reducer level before you can use it, but this at least works for your example, since xform is no longer a generic value, but a non-generic value with a generic method.
What about annotating xform explicitly?
[<GeneralizableValue>]
let xform<'t> : Reducer<'t, _, _> = map (fun i -> i + 9) >> map (fun a -> a * 5) >> map (fun s -> s + 1)
As suggested above, and in the error message itself, can you add arguments explicitly?
let xform x = x |> map ...
F# only plays along so well with point free approaches
I suspect that I am missing something very obvious here but this doesn't work:
let t = Array2D.create 1 1 1.0
for x in t do printfn "%f" x;;
It fails with
error FS0001: The type 'obj' is not compatible with any of the types float,float32,decimal, arising from the use of a printf-style format string
Interestingly using printf "%A" or "%O" prints the expected values which suggests to me that the problem is with the type inference
The corresponding code for a 1D array works fine
let t = Array.create 1 1.0
for x in t do printfn "%f" x;;
For reference this is on version 2.0 (both interactive and compiler) running on the latest mono
In .NET, a 1D array implicitly implements IList, which means it also implements (by inheritance) IEnumerable<T>. So, when you run:
let t = Array.create 1 1.0
for x in t do printfn "%f" x;;
the F# compiler emits code which gets an implementation of IEnumerable<T> (seq<T> in F#) from t, then iterates over it. Since it's able to get an IEnumerable<T> from the array, x will have type T.
On the other hand, multi-dimensional arrays (2d, 3d, etc.) only implement IEnumerable (not IEnumerable<T>) so the F# compiler infers the type of x as System.Object (or obj, in F#).
There are two solutions for what you want:
Cast each individual value within the loop, before printing it:
for x in t do printfn "%f" (x :?> float);;
Or, use Seq.cast to create and iterate over a strongly-typed enumerator:
for x in (Seq.cast<float> t) do printfn "%f" x;;
As Jack pointed out, this is a problem. One easy solution is:
let t = Array2D.create 2 2 1.0
t |> Array2D.iter (printfn "%f");;
And if you really like the for .. in .. do syntax:
type Array2DForLoopBuilder() =
member __.Zero() = ()
member __.For(a, f) = Array2D.iter f a
member __.Run e = e
let a2dfor = Array2DForLoopBuilder()
let t = Array2D.init 2 2 (fun a b -> float a + float b)
a2dfor { for x in t do printfn "%f" x }
I need to call a function that takes System.Array [] as one parameter in F#. (The function is in a library).
I need to pass an argument of type float [] [] [] but the compiler refuses to compile. To replicate the problem, I wrote the following code
let x : float [] [] = Array.init 2 (fun x -> Array.zeroCreate 3)
x :> System.Array;; // This is OK
val x : float [] [] = [|[|0.0; 0.0; 0.0|]; [|0.0; 0.0; 0.0|]|]
> x :> System.Array [];; //Error
x :> System.Array [];;
^^^^^^^^^^^^^^^^^^^^
stdin(14,1): warning FS0059: The type 'System.Array []' does not have any proper subtypes and need not be used as the target of a static coercion
x :> System.Array [];;
^^^^^^^^^^^^^^^^^^^^
stdin(14,1): error FS0193: Type constraint mismatch. The type
float [] []
is not compatible with type
System.Array []
The type 'System.Array' does not match the type 'float []'
How can I solve this problem?
Thanks in advance.
The ability to treat an 's[] as a 't[] when 's :> 't makes the .NET type system unsound (and is probably due to the fact that Java does the same thing). Unfortunately, C# follows .NET in allowing this.
Because it's a .NET runtime feature, you can also do it in F# via boxing and unboxing:
let x : float[][] = Array.init 2 (fun x -> Array.zeroCreate 3)
let x' = (box x) :?> System.Array[]
This avoids the overhead of mapping each element as in Ramon's solution.
To see why this makes the .NET type system unsound, consider this:
x'.[0] <- upcast [| "test" |] // System.ArrayTypeMismatchException
Even though we are storing a value of type System.Array into a System.Array[], we get an exception at runtime because the true type of the underlying array can't support the operation (x and x' are just two views of the same array, and obviously a string[] can't be stored into x). This unsoundness in the .NET type system therefore has the undesirable side effect of requiring additional overhead for most stores into arrays to ensure that the stored value has a type compatible with the underlying array. In my opinion, it's a good thing that F# prevents you from doing this directly.
You could do this:
let x : float [] [] = Array.init 2 (fun x -> Array.zeroCreate 3)
let toArray (xs : #System.Array []) =
Array.map (fun x -> x :> System.Array) xs
let x' : System.Array [] = toArray x
I am trying to scale a sequence by the first element of the sequence, so the first element will always be one, and then subsequent elements are a ratio of the first element to the nth element of the original sequence.
Here is my code,
open System
open System.Collections
let squish1 (x:Double seq) =
let r = (Seq.head x:Double)
Seq.fold (fun (xi:Double) (r:Double) -> xi/r);;
And I test on this little vector:-
squish1 [|5.0; 1.0; 1.0; 1.0; 1.0; 1.0|];;
I have typed everything because I get this error message
normaliseSequence.fsx(9,1): error FS0030: Value restriction. The value 'it' has been >inferred to have generic type
val it : (Double -> '_a -> Double) when '_a :> seq
Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, >add a type annotation.
But clearly I am misunderstanding because I get the error message even with everything typed. What am I missing?
Any and all advice gratefully received. Thanks
fold expects two more parameters, the seed value and the sequence. This works:
let squish1 (x:Double seq) =
let r = (Seq.head x:Double)
Seq.fold (fun (xi:Double) (r:Double) -> xi/r) 0.0 x
However, I'm guessing you probably want map instead of fold:
let squish1 (x:Double seq) =
let r = (Seq.head x:Double)
Seq.map (fun (xi:Double) -> xi/r) x
Incidentally, I would probably write it this way:
let inline squish1 (x:seq<_>) =
let r = Seq.head x
Seq.map (fun n -> n / r) x
Now it works for all types that support division.
I'm using F# v 1.9.6.2, and I've defined a very simple computation expression:
type MaybeBuilder() =
member this.Let(x, f) =
printfn "this.Let: %A" x
this.Bind(Some x, f)
member this.Bind(x, f) =
printfn "this.Bind: %A" x
match x with
| Some(x) when x >= 0 && x <= 100 -> f(x)
| _ -> None
member this.Delay(f) = f()
member this.Return(x) = Some x
let maybe = MaybeBuilder()
I've sprinkled some print statements in the code to tell me which methods are being called in a computation expression. When I execute the following statement:
maybe {
let x = 12
let! y = Some 11
let! z = Some 30
return x + y + z
}
I expect the console to print out the following:
this.Let 12
this.Bind Some 12
this.Bind Some 11
this.Bind Some 30
But my actual results are as follows:
this.Bind: Some 11
this.Bind: Some 30
In other words, F# doesn't appear to be executing the Let member. When I re-write Let to throw an exception, the code run without an exception. Additionally, when I comment out the Let member entirely, I do not get an error message stating The field, constructor or member 'Let' is not defined, and the code executes as expected.
(I've tried investigating the code with Reflector, but as is usually the case, decompiled F# is mangled beyond readability.)
It looks like the spec for computation expressions has changed. Are let bindings no longer treated as syntax sugar, and is the Let members no longer required in computation workflows?
You had the answer yourself. From the F# spec that describes how computation expressions are translated:
{| let binds in cexpr |}C = let binds in {| cexpr |}C)
So no, you don't need to define let explicitly anymore, it's translated by the compiler.
Update: this change is mentioned in the detailed release notes of the September CTP.
Correct -- you can no longer provide a binding for let :(.
See also
http://cs.hubfs.net/forums/thread/6950.aspx