I have the following issue:
I have 2 types that are paremterized and that should work with a generic function if both types have the same type parameters
type A<'a> = A of 'a
type C<'a> = C of 'a
let inline save ((A a) :A<'a>) ((C c):C<'a>) = saveToDB (a :: c :: []) |> ignore
save (A 1) (C 2)
save (A "1") (C "2")
Now imagine a function that should execute the save but with different types which will be instantiated via some indicator
let inline save indicator (otherval:C<'a>) =
match indicator with
| "i" -> save (A 1) otherval
| "s" -> save (A "s") otherval
In this case I get an error on | "s" -> adder (A "s") otherval saying that otherval should be of type C<int>
Any idea on how to approach this?
Building on Julien Roncaglia's answer, this method should at least be type-safe because we are using when guards:
let inline save ((A a) :A<'a>) ((C c):C<'a>) = saveToDB (a :: c :: []) |> ignore
let boxToGenericC<'a, 'b> (c: C<'a>) =
unbox<C<'b>>(box(c))
let save1 indicator (otherval:C<'a>) =
match indicator with
| "i" when typeof<'a> = typeof<System.Int32> -> save (A 1) (boxToGenericC<'a, int> otherval)
| "s" when typeof<'a> = typeof<string>-> save (A "s") (boxToGenericC<'a, string> otherval)
and attemping to do save1 "s" (C 1) gives a pattern match failure.
While it might not be a "clean" design (And I don't see one without changing your specification) you can just tell the type system to stop caring :
let inline firstval indicator:A<'a> =
let boxed =
match indicator with
| "i" -> box (A 1)
| "s" -> box (A "s")
unbox<A<'a>> boxed
let inline save2 indicator (otherval:C<'a>) =
save (firstval indicator) otherval
save2 "i" (C 2)
save2 "s" (C "2")
It works but you lose some checking:
save2 "s" (C 1)
Unable to cast object of type 'A`1[System.String]' to type 'A`1[System.Int32]'.
Related
I read the following type definition. What does it do?
type StreamCell<'a> =
| Nill
| Cons of 'a * Stream<'a>
and Stream<'a> = Lazy<StreamCell<'a>>
I tried to define the value with the type.
let x = Lazy(1::2::Nill) // Type is Lazy<list<int>>
let y = Lazy(Nill::1) // Lazy<StreamCell<obj>>
I thought the type of x and y should be StreamCell?
The and in F# exists to define recursive types. In most other languages there exists no order. Once you define a class, function and so on. You can access it. But in F# order is important. You only can access thinks that are already defined.
Because of this, usually it would not be possible to define recursive types, or in generall circular types. What i think is a good idea. But sometimes, you want this, and in this case, you must define the types that should be recursive with an and.
A simple example would be
type A = A of B
type B = B of A
and this will fail. Because when you define A, there is no B. So B must be defined before A. But you cannot define B before A because it depends on A.
So instead of using type you use and instead.
type A = A of B
and B = B of A
You cannot create a value of this type because it would be infinite, but it's only for understanding the problem. Next, your example is not the best, because.
and Stream<'a> = Lazy<StreamCell<'a>>
is only a Type Alias. Here you define Stream<'a> as an alias to Lazy<StreamCell<'a>>. But the compiler will usually not use Stream<'a>. This only helps if you would write the type manually in your function definitions. Your definition could also be.
type StreamCell<'a> =
| Nill
| Cons of 'a * Lazy<StreamCell<'a>>
In your example
let x = Lazy(1::2::Nill)
You use :: and this IS NOT the Cons you define with your stream. You will use the cons operator that is defined with F#, and that is the built-in list. This is the reason why you see Lazy<List<int>> as a type.
If you want to define your stream with two values you need to write.
let x = Cons(1,lazy Cons(2, lazy Nill))
As a general note i would rename Cons to Next or something else. To avoid confusion and create helper function to create Nill and Next values.
Addition
and can also be used to change the Order of definition, and make it more obvious, which types belong together.
type Person = {
Name: string
Sex: Sex
}
and Sex =
| Male
| Female
let person = { Name="David"; Sex=Male }
Example
Here is a full-blown example how i would do a Stream type on what you provided.
type Stream<'a> =
| Nill
| Next of 'a * Lazy<Stream<'a>>
let nill = Nill
let next h t = Next(h,t)
let rec unfold gen state =
match gen state with
| None -> Nill
| Some(x,state) -> next x (lazy unfold gen state)
let rec fold f acc xs =
match xs with
| Nill -> acc
| Next(h,t) -> fold f (f acc h) (t.Force())
let rec rev stream =
fold (fun acc x -> next x (lazy acc)) nill stream
let toList stream =
fold (fun acc x -> x::acc ) [] (rev stream)
let rec take x stream =
if x > 0 then
match stream with
| Nill -> Nill
| Next(h,t) -> next h (lazy take (x-1) (t.Force()))
else
Nill
let fromTo start stop =
unfold (fun acc -> if acc<stop then Some(acc,acc+1) else None) start
let x = next 1 (lazy next 2 (lazy next 3 (lazy nill)))
let y = next 1.0 (lazy next 2.0 (lazy next 3.0 (lazy nill)))
printfn "%A" (toList (take 2 x))
printfn "%A" (toList (take 2 y))
printfn "%A" (toList (take 2 (fromTo 1 100)))
printfn "%A" (toList (take 5 (fromTo 1 1_000_000_000)))
On page 209 - 210 there is an extended example (see below) (I'm using F# 4.5).
In summary what I don't understand is: if I type each statement individually, there is a declaration that raises an error. If I submit the whole script at once, with the functions that come after the declaratation that raises the error, everything is OK. So what happens in interactive when I submit all the statements as a batch? Does the function that follows the error get used to create a specific version of the potential generic? The ionide hints do not show a generic for the whole script.
In detail (sorry it's so long)
If you execute each of the statements in order upto and including the declaration of formatP , (or paste all of them upto and including formatP at once - e.g. select and alt-enter with ionide in vs code) in interactive, it produces an error:
binary.fsx(67,5): error FS0030: Value restriction. The value 'formatP' has been inferred to have generic type
val formatP : ((int * bool) list -> '_a -> unit) when '_a :> OutState
Either make the arguments to 'formatP' explicit or, if you do not intend for it to be generic, add a type annotation.
if you paste all of the script including the functions which follow formatP
let writeData file data =
use outStream = BinaryWriter(File.OpenWrite(file))
formatP data outStream
let readData file =
use inStream = BinaryReader(File.OpenRead(file))
formatU inStream
it works without error.
Given that compilation order is important - what is happening here?
i.e. why do the functions that are declared after formatP allow the function to compile.
Whole script - which functions without error (It's a bit long - but because I really don't understand the issue, I'm not sure what I can remove to create an accurate example illustrating what is happening.
I guess I could drop formatU and readData? (which have the same relationship) but they are needed to make the last 2 stamenets work which sahows that the code does complie and execute as expected):
open System.IO
type OutState = BinaryWriter
type InState = BinaryReader
type Pickler<'T> = 'T -> OutState -> unit
type Unpickler<'T> = InState -> 'T
// P is the suffix for pickling and U is the suffix for unpickling
let byteP (b : byte) (st : OutState) = st.Write(b)
let byteU (st : InState) = st.ReadByte()
let boolP b st = byteP (if b then 1uy else 0uy) st
let boolU st = let b = byteU st in (b = 1uy)
let int32P i st =
byteP (byte (i &&& 0xFF)) st
byteP (byte ((i >>> 8) &&& 0xFF)) st
byteP (byte ((i >>> 16) &&& 0xFF)) st
byteP (byte ((i >>> 24) &&& 0xFF)) st
let int32U st =
let b0 = int (byteU st)
let b1 = int (byteU st)
let b2 = int (byteU st)
let b3 = int (byteU st)
b0 ||| (b1 <<< 8) ||| (b2 <<< 16) ||| (b3 <<< 24)
let tup2P p1 p2 (a, b) (st : OutState) =
(p1 a st : unit)
(p2 b st : unit)
let tup3P p1 p2 p3 (a, b, c) (st : OutState) =
(p1 a st : unit)
(p2 b st : unit)
(p3 c st : unit)
let tup2U p1 p2 (st : InState) =
let a = p1 st
let b = p2 st
(a, b)
let tup3U p1 p2 p3 (st : InState) =
let a = p1 st
let b = p2 st
let c = p3 st
(a, b, c)
/// Outputs a list into the given output stream by pickling each element via f.
/// A zero indicates the end of a list, a 1 indicates another element of a list.
let rec listP f lst st =
match lst with
| [] -> byteP 0uy st
| h :: t -> byteP 1uy st; f h st; listP f t st
// Reads a list from a given input stream by unpickling each element via f.
let listU f st =
let rec loop acc =
let tag = byteU st
match tag with
| 0uy -> List.rev acc
| 1uy -> let a = f st in loop (a :: acc)
| n -> failwithf "listU: found number %d" n
loop []
type format = list<int32 * bool>
//the types in these two lines only get fully inferred if the lines after are part of the batch
//eh?
let formatP = listP (tup2P int32P boolP)
let formatU = listU (tup2U int32U boolU)
//IE if you only run to here it is an error
let writeData file data =
use outStream = BinaryWriter(File.OpenWrite(file))
formatP data outStream
let readData file =
use inStream = BinaryReader(File.OpenRead(file))
formatU inStream
//If you run to here it does not error
writeData "out.bin" [(102, true); (108, false)] ;;
readData "out.bin"
There are two things going on here, only one of which I can fully explain.
The first is the F# value restriction. In this case, the compiler infers that listP is a generic function, which also makes the value formatP generic. But F# doesn't allow a generic value in this situation, so a compiler error occurs. However, when writeData is present, formatP is no longer generic, so the compiler error disappears. You can see a very similar situation explained in detail here.
But why does the compiler think listP is generic in the first place? I'm not sure about this. It infers that st must be compatible with OutState, which is correct from an object-oriented point of view. But it expresses this as a generic constraint, using st : #OutState instead of just st : OutState. (F# calls this a "flexible type".) This generic constraint then cascades to formatP, causing the problem you reported. Someone with more knowledge of the F# compiler might be able to explain this.
Here's a very small example that exhibits the same behavior:
type Example() = class end
let alpha (_ : Example) =
()
let beta f x =
alpha (f x)
let gamma = beta id
// let delta = gamma (Example())
The compiler infers a generic type for beta, which makes gamma illegal when delta is commented out.
To make matters stranger, the same problem occurs even if I explicitly annotate beta so it's not generic:
let beta (f : Example -> Example) (x : Example) =
alpha (f x)
So the compiler thinks gamma is generic even when beta definitely isn't generic. I don't know why that is.
I'm trying to create a function that takes in a variable amount of parameters but I can't seem to find any viable solution for F#.
let expression = (fun a b -> a || b)
let expressionTriple = (fun a b c -> (a || b) && c)
// This doesn't work because expression can either be a function that takes fixed arguments
let truthTable numPredicates expression =
if numPredicates = 2 then
expression true true
else
expression true true false
truthTable 2 expression
truthTable 3 expressionTriple
How can I pass in a variable amount of arguments into the expression function?
In F#, functions with different signatures (including a different number of parameters) are considered distinct types. And any time you want to have a function take a parameter that could be two distinct types (or even a dozen distinct types), you need to use discriminated unions. Here's how you could write your code in a way that will compile and do what you're trying to do:
type Expression<'a> =
| Double of ('a -> 'a -> 'a)
| Triple of ('a -> 'a -> 'a -> 'a)
let expression = fun a b -> a || b
let expressionTriple = fun a b c -> (a || b) && c
// This works because expression is a discriminated union
let truthTable expression =
match expression with
| Double f -> f true true
| Triple f -> f true true false
truthTable (Double expression)
truthTable (Triple expressionTriple)
If you wanted to add a four-parameter version, just add a Quad of ('a -> 'a -> 'a -> 'a -> 'a) case to that discriminated union, and so on.
If you have any questions about this, like why I wrote this with generic type 'a instead of bool, please feel free to ask follow-up questions.
let expression = (fun [a; b] -> a || b)
let expressionTriple = (fun [a; b; c] -> (a || b) && c)
let truthTable numPredicates expression =
if numPredicates = 2 then
expression [true; true]
else
expression [true; true; false]
truthTable 2 expression
truthTable 3 expressionTriple
I'd like to check that a value is of a particular case of a discriminated union, without having to also check any included data. My motivation is to only test one thing with each unit test.
An example is as follows (the last two lines give compilation errors):
module MyState
open NUnit.Framework
open FsUnit
type MyState =
| StateOne of int
| StateTwo of int
let increment state =
match state with
| StateOne n when n = 10 -> StateTwo 0
| StateOne n -> StateOne (n + 1)
| StateTwo n -> StateTwo (n + 1)
[<Test>]
let ``incrementing StateOne 10 produces a StateTwo`` ()=
let state = StateOne 10
(increment state) |> should equal (StateTwo 0) // works fine
(increment state) |> should equal (StateTwo _) // I would like to write this...
(increment state) |> should be instanceOfType<StateTwo> // ...or this
Can this be done in FsUnit?
I'm aware of this answer but would prefer not to have to write matching functions for each case (in my real code there are far more than two).
If you don't mind using reflections, the isUnionCase function from this answer could be handy:
increment state
|> isUnionCase <# StateTwo #>
|> should equal true
Note that it's a bit verbose because you need a function call before comparing values.
A similar but lighter approach could be comparison of tags:
// Copy from https://stackoverflow.com/a/3365084
let getTag (a:'a) =
let (uc,_) = Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields(a, typeof<'a>)
uc.Name
increment state
|> getTag
|> should equal "StateTwo"
Beware that this is not type-safe and you can easily misspell a union case name.
What I would do is to create a similar DUs for comparison purpose:
type MyStateCase =
| StateOneCase
| StateTwoCase
let categorize = function
| StateOne _ -> StateOneCase
| StateTwo _ -> StateTwoCase
In this way, you define categorize once and use it multiple times.
increment state
|> categorize
|> should equal StateTwoCase
It appears FSUnit doesn't (or can't, I'm not sure) directly support this use case.
The next best thing I've found is to declare a TestResult type like the following and use a match to reduce the result to this type.
type TestResult =
| Pass
| Fail of obj
Here is the reducing match
let testResult =
match result with
| OptionA(_) -> Pass
| other -> Fail(other)
Now you can just use should equal to ensure the correct result.
testResult |> should equal Pass
The benefits of this solution are strong typing but more importantly in the failure case you can see what the invalid result was.
It doesn't look very elegant, but you can extract type from a value of state:
let instanceOfState (state: 'a) =
instanceOfType<'a>
And then use it in the test:
(increment state) |> should be (instanceOfState <| StateTwo 88)
EDIT
Yes, unfortunately the type is always MyState. Looks like pattern matching or ugly reflection are inevitable.
What if FsUnit already supports an assertion against a specific union case, albeit one restricted to values of the type Microsoft.FSharp.Core.Choice<_,...,_>?
Let's leverage this with a multi-case active pattern, which uses Reflection to check against the union case name.
open System.Reflection
open Microsoft.FSharp.Reflection
let (|Pass|Fail|) name (x : obj) =
let t = x.GetType()
if FSharpType.IsUnion t &&
t.InvokeMember("Is" + name,
BindingFlags.GetProperty, null, x, null )
|> unbox then Pass
else Fail x
Should be working now:
increment state
|> (|Pass|Fail|) "StateTwo"
|> should be (choice 1)
I feel silly for even asking this because it seems so trivial but my brain is failing me. If I had the following:
let a, b, c = 1, 1, 1
Is there an eligant way to determine if a, b, and c all hold the same value. Something like:
let result = (a = b = c)
This fails because the expression a = b returns true and the next expression results in true = c and complains that it was expecting int, not bool. The only thing I can think of is:
a = b && a = c && b = c
which won't work when I want to add more variables.
Really what I'm trying to do is this:
let same (x: string * string * string) =
match x with
| (a, a, a) -> true
| _ -> false
I was hoping that I could match all the elements into one element and if they were different it would move on, but it says on the second element in the match that it has already been bound.
To check if every value in a list is the same:
let rec same = function
| x::y::_ when x <> y -> false
| _::xs -> same xs
| [] -> true
Usage
let a, b, c = 1, 1, 1
same [a; b; c] //true
let same (a, b, c) = a = b && b = c
I would try to use the forall function in order to determine if all of the numbers are same.
let list = [a; b; c;];;
List.forall (fun n -> n = a) list;;
val it : bool = true
This solution produces exactly the required syntax. Surprisingly to myself, is fairly fast. Also, is seems to be a good example of using monads, also known as Computation Expressions.
// Generic
let inline mOp1<'a> op sample x = op sample x, sample
let inline mOp2<'a> op1 op2 (b, sample) x = op1 b (op2 sample x), sample
// Implementation for (=) and (&&)
let (==) = mOp1 (=)
let (&=) = mOp2 (&&) (=)
// Use
let ret1 = a == b &= c &= d &= e |> fst
How it works
The approach is a very simplified State monad. The monadic type is a tuple of (bool, 'T). The first component is the boolean value of ongoing calculation, and the second is the sample value to compare with.
(==) would initialize the monad, similar to Delay operator.
(&=) is used for all subsequent comparisons. It is similar to Bind operator.
We don't need Return because fst would serve pretty fine.
mOp1 and mOp2 are abstractions over the logical operations. These allow defining your own operators. Here are examples of or-equal and and-greater-than:
let (|=) = mOp2 (||) (=)
let (.>) = mOp1 (>)
let (&>) = mOp2 (&&) (>)
// Use
let ret2 = a == b |= c |= d |= e |> fst // if any of b,c,d,e equals to a
let ret3 = 5 .> 3 &> 4 |> fst // true: 5>3 && 5>4
let ret4 = 5 .> 3 &> 8 &> 4 |> fst // false
Performance
I really enjoyed the beautiful solution by #ildjarn, but constructing List is quite slow, so my primary goal was performance.
Running a chain of 8 comparisons, 10 million times:
04972ms a=b && a=с && ...
23138ms List-based
12367ms monadic