I have an xUnit test that accepts three arguments, a list, an integer and a tuple, however, when I run it it's failing with the following error:
System.InvalidOperationException: The test method expected 4 parameter values, but 3 parameter values were provided.
There are only three items in the test data I'm providing.
[<AbstractClass>]
type TestCases (data: seq<obj[]>) =
member this.Data = data
interface IEnumerable<obj[]> with
member this.GetEnumerator() = this.Data.GetEnumerator()
interface IEnumerable with
member this.GetEnumerator() = (this :> IEnumerable).GetEnumerator()
type SplicingTestCases () =
inherit TestCases (seq {
yield [|box [1; 2; 3; 4;];
box 2;
box ([1;2;],[3;4;])
|]
})
[<Theory>]
[<ClassData(typeof<SplicingTestCases>)>]
let ``Splicing`` testList index expected =
let actual = testList |> splice index
Assert.Equal(expected, actual)
I've exec tried removing a parameter (just to see what happens) like this:
let ``Splicing`` testList index =
let actual = testList |> splice index
Assert.Equal(actual, actual)
Now the error is:
System.InvalidOperationException: The test method expected 2 parameter values, but 3 parameter values were provided.
Any suggestions?
Looks like the tuple is being converted into two separate objects. Not sure yet if this is happening in the F# compilation of in xUnit's interpretation of the tuple.
Yielding the following works though:
[|box [1; 2; 3; 4;];
box 2;
box [1;2;];
box [3;4;];|]
Related
I am new in F# and I wonder whether is there a possibility (unsing NUnit) to construct a test class multiple parameters in its constructor with some similar construction - following end up with
Message:
OneTimeSetUp: No suitable constructor was found
// if data with one parameter, no problem to run the tests
// the data not only the constants at the compile time, so need to work TestFixtureSoource attribute.
type SimpleFixtureArgs =
static member Source = [| (String.Empty, String.Empty); ("hello", "hello") |]
[<TestFixtureSource(typeof<SimpleFixtureArgs>, "Source")>]
type ``simple tests class``(text, text2) =
[<Test>]
member this.``simple test``() =
let expexted = text
let actual = text2
Assert.AreEqual(expexted, actual)
Since removing the one parameter (e.g. the text2) and having appropriate one-parameter TestFixtureSource it started to work...
So the question is how to write the NUnit test to work with TestFixtureSource with multiple parameters?
TIA,
Mojmir
Individual items of text fixture source should be object arrays or derive from the TestFixtureParameters class (NUnit documentation). But tuple is not an object array - it's a single object. So change source property to return IEnumerbale (or array) of arrays:
type SimpleFixtureArgs =
static member Source = seq {
[| String.Empty; String.Empty|]
[| "hello"; "hello"|]
}
Later, I needed to deal with different types of parameters.
There is slightly modified code in F# from the previous answer, which worked for me.
type SimpleFixtureArgs2 =
static member Source : seq<obj []> =
seq {
yield [| String.Empty; String.Empty; 1; 1 |]
yield [| "hello"; "hello"; 2; 2 |]
}
[<TestFixtureSource(typeof<SimpleFixtureArgs2>, "Source")>]
type ``simple tests2 class``(text1, text2, num1, num2) =
[<Test>]
member this.``simple strings and integers test``() =
let expextedText = text1
let actualText = text2
Assert.AreEqual(expextedText, actualText)
Assert.AreEqual(num1, num2)
I'd like to create a type with a definition a bit like this:
type LeftRight<'left, 'right> = {
Left : 'left list
Right : 'right list
}
and a couple of functions:
let makeLeft xs = { Left = xs; Right = [] }
let makeRight ys = { Left = []; Right = ys }
and I'd like to provide a 'combiner' function:
let combine l r = { Left = l.Left # r.Left; Right = l.Right # r.Right }
When I try and make something, I (obviously!) get issues as my value is generic:
let aaa = makeLeft [1;2;3]
// Value restriction. The value 'aaa' has been inferred to have generic type
// val aaa : LeftRight<int,'_a>
If I combine a left and a right, type inference kicks in and everything's A-OK:
let bbb = makeRight [1.0;2.0;3.0]
let comb = combine aaa bbb // LeftRight<int, float>
but I want to use one with only lefts on its own. I tried creating an 'Any' type:
type Any = Any
and explicitly specified the types on makeLeft and makeRight:
let makeLeft xs : LeftRight<_, Any> = { Left = xs; Right = [] }
let makeRight ys : LeftRight<Any, _> = { Left = []; Right = ys }
which makes the value definitions happy, but makes the combine function sad:
let combined = combine aaa bbb
// Type mismatch. Expecting a
// LeftRight<int,Any>
// but given a
// LeftRight<Any,float>
// The type 'int' does not match the type 'Any'
I feel like there's probably a way around this with loads of voodoo with .Net's overloading of function calls, but I can't make it work. Has anyone tried this before/have any ideas?
The value restriction is not a problem in this case, you need the result of makeLeft or makeRight be generic if you ever hope to use them generically further down the line.
In F# (and OCaml), generic syntactic values must be explicitly marked as such, with full type annotations. Indeed, the compiler reports this:
error FS0030: Value restriction. The value 'aaa' has been inferred to
have generic type
val aaa : LeftRight Either define 'aaa' as a simple data term, make it a function with explicit arguments or, if you do
not intend for it to be generic, add a type annotation.
Without going into too much detail*, this is to avoid issues that can occur when combining polymorphism and side effects. The downside is that it does reject some perfectly safe code as a result.
So, the solution is simple, we make these values explicitly generic:
let aaa<'a> : LeftRight<int,'a> = makeLeft [1;2;3]
let bbb<'a> : LeftRight<'a, float> = makeRight [1.0;2.0;3.0]
Putting them together in FSI:
let comb = combine aaa bbb;;;
val comb : LeftRight<int,float> = {Left = [1; 2; 3];
Right = [1.0; 2.0; 3.0];}
Note that if you combine without intermediate let bindings, you no longer have a generic value and the proper type can be inferred by the compiler:
combine (makeLeft [1;2;3]) (makeRight [1.0;2.0;3.0]);;
val it : LeftRight<int,float> = {Left = [1; 2; 3];
Right = [1.0; 2.0; 3.0];}
*For more detail, check out this article.
Learning F# as part of my course, and can do some cool things, but something has been bugging me, whenever I use the val keyword, I get an error. I think it could be due to not declaring something in script, but I don't really know.
module Prime
#light
let nums = [1; 2; 3; 4; 5];;
val nums : list<int>
let rec sum list =
match list with
| h::tail -> (sum tail) + h
| [] -> 0
val sum : list<int> -> int
I get (line 5):
Error 1 Unexpected keyword 'val' in definition . Expected incomplete structured construct at or before this point or other token
Any ideas?
The val keyword in F# (unlike 'val' in ML) is used to declare a field in a class or structure type without initializing it.
http://msdn.microsoft.com/en-us/library/dd469494.aspx
if you want to define mutable value in the Module you can use
let mutable...
By the way, if you define the value with the same name (like 'nums') twice or more times then the effective value for the compiler will be latest defined in the scope.
So actually, I had misread the coursework set out, annoyingly the papers use val to define what the expected output of the function is, as opposed to using it as the keyword it is meant to be. Hence my confusion and lots of head scratching.
This looks like F# interactive output mixed in with code.
If I type this into FSI:
let nums = [1; 2; 3; 4; 5];;
The output is
val nums : int list = [1; 2; 3; 4; 5]
Note that ;; is where FSI parses and runs input. You wouldn't have this in non-interactive code. The output might differ because of an older version or editing, but nontheless, it doesn't belong in code.
Coincidentally, val is also a rarely used F# keyword for explicit fields. Hence the strange error message.
The val keyword is used to declare a field ; it must be used inside a type definition (class or structure). Since in your code the variable nums is already defined and as the list type inferred by F# type inference engine, there is no need for your val line.
An example of val keyword usage is (from msdn) :
type MyType() =
let mutable myInt1 = 10
[<DefaultValue>] val mutable myInt2 : int
[<DefaultValue>] val mutable myString : string
member this.SetValsAndPrint( i: int, str: string) =
myInt1 <- i
this.myInt2 <- i + 1
this.myString <- str
printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)
I'm reading Expert F# book and I found this code
open System.Collections.Generic
let divideIntoEquivalenceClasses keyf seq =
// The dictionary to hold the equivalence classes
let dict = new Dictionary<'key,ResizeArray<'T>>()
// Build the groupings
seq |> Seq.iter (fun v ->
let key = keyf v
let ok,prev = dict.TryGetValue(key)
if ok then prev.Add(v)
else let prev = new ResizeArray<'T>()
dict.[key] <- prev
prev.Add(v))
dict |> Seq.map (fun group -> group.Key, Seq.readonly group.Value)
and the example use:
> divideIntoEquivalenceClasses (fun n -> n % 3) [ 0 .. 10 ];;
val it : seq<int * seq<int>>
= seq [(0, seq [0; 3; 6; 9]); (1, seq [1; 4; 7; 10]); (2, seq [2; 5; 8])]
first for me this code is really ugly, even if this is safe, It looks more similar to imperative languages than to functional lang..specially compared to clojure. But the problem is not this...I'm having problems with the Dictionary definition
when I type this:
let dict = new Dictionary<'key,ResizeArray<'T>>();;
I get this:
pruebafs2a.fs(32,5): error FS0030: Value restriction. The value 'dict' has been inferred to have generic type
val dict : Dictionary<'_key,ResizeArray<'_T>> when '_key : equality
Either define 'dict' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
is It ok?...
thanks so much
improve question:
Ok I've been reading about value restriction and I found this helpfull information
In particular, only function definitions and simple immutable data
expressions are automatically generalized
...ok..this explains why
let dict = new Dictionary<'key,ResizeArray<'T>>();;
doesn't work...and show 4 different techniques, although in my opinion they only resolve the error but aren't solutions for use generic code:
Technique 1: Constrain Values to Be Nongeneric
let empties : int list [] = Array.create 100 []
Technique 3: Add Dummy Arguments to Generic Functions When Necessary
let empties () = Array.create 100 []
let intEmpties : int list [] = empties()
Technique 4: Add Explicit Type Arguments When Necessary (similar to tec 3)
let emptyLists = Seq.init 100 (fun _ -> [])
> emptyLists<int>;;
val it : seq<int list> = seq [[]; []; []; []; ...]
----- and the only one than let me use real generic code ------
Technique 2: Ensure Generic Functions Have Explicit Arguments
let mapFirst = List.map fst //doesn't work
let mapFirst inp = List.map fst inp
Ok, in 3 of 4 techniques I need resolve the generic code before can work with this...now...returning to book example...when the compile knows the value for 'key and 'T
let dict = new Dictionary<'key,ResizeArray<'T>>()
in the scope the code is very generic for let key be any type, the same happen with 'T
and the biggest dummy question is :
when I enclose the code in a function (technique 3):
let empties = Array.create 100 [] //doesn't work
let empties () = Array.create 100 []
val empties : unit -> 'a list []
I need define the type before begin use it
let intEmpties : int list [] = empties()
for me (admittedly I'm a little dummy with static type languages) this is not real generic because it can't infer the type when I use it, I need define the type and then pass values (not define its type based in the passed values) exist other way define type without be so explicit..
thanks so much..really appreciate any help
This line
let dict = new Dictionary<'key,ResizeArray<'T>>();;
fails because when you type the ;; the compiler doesn't know what 'key and 'T are. As the error message states you need to add a type annotation, or allow the compiler to infer the type by using it later or make it a function
Examples
Type annotation change
let dict = new Dictionary<int,ResizeArray<int>>();;
Using types later
let dict = new Dictionary<'key,ResizeArray<'T>>()
dict.[1] <- 2
using a function
let dict() = new Dictionary<'key,ResizeArray<'T>>();;
This actually doesn't cause an issue when it's defined all together. That is, select the entire block that you posted and send it to FSI in one go. I get this:
val divideIntoEquivalenceClasses :
('T -> 'key) -> seq<'T> -> seq<'key * seq<'T>> when 'key : equality
However, if you type these individually into FSI then as John Palmer says there is not enough information in that isolated line for the interpreter to determine the type constraints. John's suggestions will work, but the original code is doing it correctly - defining the variable and using it in the same scope so that the types can be inferred.
for me this code is really ugly, even if this is safe, It looks more similar to imperative languages than to functional lang.
I agree completely – it's slightly tangential to your direct question, but I think a more idiomatic (functional) approach would be:
let divideIntoEquivalenceClasses keyf seq =
(System.Collections.Generic.Dictionary(), seq)
||> Seq.fold (fun dict v ->
let key = keyf v
match dict.TryGetValue key with
| false, _ -> dict.Add (key, ResizeArray(Seq.singleton v))
| _, prev -> prev.Add v
dict)
|> Seq.map (function KeyValue (k, v) -> k, Seq.readonly v)
This allows sufficient type inference to obviate the need for your question in the first place.
The workarounds proposed by the other answers are all good. Just to clarify based on your latest updates, let's consider two blocks of code:
let empties = Array.create 100 []
as opposed to:
let empties = Array.create 100 []
empties.[0] <- [1]
In the second case, the compiler can infer that empties : int list [], because we are inserting an int list into the array in the second line, which constrains the element type.
It sounds like you'd like the compiler to infer a generic value empties : 'a list [] in the first case, but this would be unsound. Consider what would happen if the compiler did that and we then entered the following two lines in another batch:
empties.[0] <- [1] // treat 'a list [] as int list []
List.iter (printfn "%s") empties.[0] // treat 'a list [] as string list []
Each of these lines unifies the generic type parameter 'a with a different concrete type (int and string). Either of these unifications is fine in isolation, but they are incompatible with each other and would result in treating the int value 1 inserted by the first line as a string when the second line is executed, which is clearly a violation of type safety.
Contrast this with an empty list, which really is generic:
let empty = []
Then in this case, the compiler does infer empty : 'a list, because it's safe to treat empty as a list of different types in different locations in your code without ever impacting type safety:
let l1 : int list = empty
let l2 : string list = empty
let l3 = 'a' :: empty
In the case where you make empties the return value of a generic function:
let empties() = Array.create 100 []
it is again safe to infer a generic type, since if we try our problematic scenario from before:
empties().[0] <- [1]
List.iter (printfn "%s") (empties().[0])
we are creating a new array on each line, so the types can be different without breaking the type system.
Hopefully this helps explain the reasons behind the limitation a bit more.
Suppose I have type A with indexer implemented, e.g. type A is a library. Now I want to extend the indexer of it, e.g. here I want to add float number into the indexer.
I worked out the following code:
type A(a:int array) =
member this.Item
with get(x) = a.[x]
and set(x) value = a.[x] <- value
type A with
member m.Item with
get(x:float) = m.[x |> int]
and set(x:float) v = m.[x |> int] <- v
But it seems not working:
let a = A([| 1;2;3 |])
a.[1]
a.[1] <- 10
a.[1.0]
For the last line, I get:
Script1.fsx(243,4): error FS0001: This expression was expected to have type
int
but here has type
float
Is extending indexer possible in F#? Thanks!
This behaves differently when the type extension is defined in a separate assembly (or separate module) and when it is in the same module as the type definition.
When both are in the same module, F# compiles them into a single class and Item becomes a standard overloaded indexer - In this case, your code works as expected (and this is how you actually wrote it here).
When they are in separate modules, F# compiles the indexer as an extension member. In this case, I get the error message you described.
Adding new overloads using extension members (e.g. new method) is possible. As far I can see, the specificaton doesn't say that this shouldn't work for indexers, so I think it is a bug (can you report it to fsbugs at microsoft dot com?)
I just tried this in FSI and it seems to work.
What compiler are you using?
This is what I fed to FSI:
type A(a:int array) =
member this.Item
with get(x) = a.[x]
and set(x) value = a.[x] <- value
type A with
member m.Item
with get(x:float) = m.[x |> int]
and set(x:float) v = m.[x |> int] <- v
let a = A([| 1;2;3 |])
a.[1] <- 10
printfn "%A" a.[1.2]
This prints '10'