let's consider this code:
type T =
{
a: int
}
let d =
[
"a", [{a = 0}; {a = 1}; {a = 2}]
"b", [{a = 3}; {a = 4}; {a = 5}]
] |> Map
If I want to access the data with a = 0:
d.["a"].[0].a <- works
d["a"].[0].a <- now works with F#6
d["a"][0] <- returns {a = 0}
but
d["a"][0].a <- typecheck error This value is not a function and cannot be applied.
if I wrap the expression in parenthesis:
(d["a"][0]).a <- it works
Is this expected, or could it be a F#6 parsing bug?
In the end, this was done for compatibility reasons; see the reply by Don Syme:
https://github.com/dotnet/fsharp/issues/12549#event-5840475607
A request to allow this notation was posted and seems approved.
https://github.com/fsharp/fslang-suggestions/issues/1109
Related
I get a IEnumerable of object from using a SqlCommandProvider. Those objects match my rows and columns. Lets called it B. In my program I created a type matching those columns too. Lets call this record A. How can I actually transform/cast/construct a record c of type A based on values from B?
type A = {k: int; c: string}
let a:A = { k = 1; c = "c" }
let b = {| k = 1; c = "c" |} // lets say that this one simulate the sql's object
let c:A = b
printfn "%A" a
printfn "%A" b
printfn "%A" c
Try it online!
I got an error of type mismatch:
error FS0001: This expression was expected to have type 'A' but here has type '{|c : string ; k : int|}'
Full sample code with the provider:
type A = {k: int; c: string}
let toA c =
(A)c // ???
do
use cmd = new SqlCommandProvider<"
SELECT k, c
FROM Examples
" , connectionString>(connectionString)
cmd.Execute() |> Seq.map toA
sql table if it matters:
k
c
0
a
1
b
I read the doc without finding a solution to my problem. Maybe it is a comprehension problem.
A working solution is to construct a record from the object:
let toA c =
{k = c.k; c = c.c }
cmd.Execute()
|> Seq.map toA
I can't give an explanation to this error (F# 4.1 in VS 2017).
Common code:
open Eto.Forms
type MyCommand() as this =
inherit Eto.Forms.Command()
do
this.MenuText <- "C&lick Me, Command"
this.ToolBarText <- "Click Me"
this.ToolTip <- "This shows a dialog for no reason"
this.Shortcut <- Application.Instance.CommonModifier ||| Keys.M
The following declaration is not accepted by the F# editor; the error message detected in the Menu initialization is "Named arguments must appear after all other arguments":
type MyForm1() =
inherit Eto.Forms.Form(
Title = "Eto Tests"
, ClientSize = Eto.Drawing.Size(600, 400)
, Menu = seq {yield new MyCommand()} |> Seq.fold (fun (mb:MenuBar) c -> mb.Items.Add(c) |> ignore; mb) (new MenuBar())
)
The following declaration works without errors instead:
type MyForm1() =
inherit Eto.Forms.Form(
Title = "Eto Tests"
, ClientSize = Eto.Drawing.Size(600, 400)
, Menu = let m = seq {yield new MyCommand()} |> Seq.fold (fun (mb:MenuBar) c -> mb.Items.Add(c) |> ignore; mb) (new MenuBar()) in m
)
Thanks in advance.
It looks like certain characters in the parameter value stump the parser and it parses the whole thing as a comparison (i.e. x = y), and since that's a boolean value, it assumes that it must be value of an unnamed parameter, hence the error.
I couldn't find any mentions of this in the F# spec, but my experiments so far have revealed that the list of offending characters includes (but is not limited to) <, >, $, and &. The plus sign + and curly braces { } are not in the list.
type T = T with static member M(x: int, y: bool, z: int seq) = ()
let inline ($) a b = a + b
T.M(
y = true, z = [],
x = 5 $ 4 // Fails
)
T.M(
y = true, z = [],
x = 5 + 4 // Works
)
T.M(
y = true, x = 5,
z = seq { yield 5 } // Works
)
T.M(
y = true, z = [],
x = seq { yield 5 } |> Seq.head // Fails due to the `>` symbol in the pipe
)
T.M(
x = 5, z = [],
y = 4 < 3 // Fails
)
T.M(
x = 5, z = [],
y = true & false // Fails
)
Fortunately, there is a workaround: enclose the whole value in a pair of parentheses. That helps the parser correctly determine where the value is.
I'm trying to understand how to use F# computation expressions and it certainly puzzles me.
The following example makes some amount of sense to me.
type ListMonad() =
member o.Bind( (m:'a list), (f: 'a -> 'b list) ) = List.collect f m
member o.Return(x) = [x]
let list = ListMonad()
let test =
list {
let! x = [ 1 .. 10]
let! y = [2 .. 2 .. 20]
return (x,y)
}
My question is, how would you add a condition to this computation expression? Specifically, how would you alter it to return a list of elements only where the x value is strictly smaller than the y value? (Let's not filter it out afterward).
Since computation expressions can be parameterized, you might first think to try something like this:
let filterAndCollect (pred : 'a -> 'b -> bool) (f : 'a -> 'b list) (m : 'a list) =
let f' a = [ for b in f a do if pred a b then yield b ]
List.collect f' m
type FilteringListMonad(pred) =
member o.Bind( (m:'a list), (f: 'a -> 'b list) ) = filterAndCollect pred f m
member o.Return(x) = [x]
let filteredList = FilteringListMonad(fun x y -> x < y)
let test2 =
filteredList {
let! x = [1 .. 10]
let! y = [2 .. 2 .. 20]
return (x,y)
}
However, that fails with a type error on the (x,y) tuple:
This expression was expected to have type 'int' but here has type ''a * 'b'
There are also two compiler warnings: on the y of the x < y expression in the FilteringListMonad constructor, there's a warning:
This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type ''b'.
And on the number 1 in the let! x = [1 .. 10] expression, there's a warning:
This construct causes code to be less generic than indicated by the type annotations. The type variable 'b has been constrained to be type 'int'.
So between these two constraints, the return type of the computation expression (a 'b list) has been constrained to be int list, but your expression is returning a int * int list instead. After some thinking about the type constraints, you might conclude that there's no way this can work. But there's a way to make it work. The key is to realize that the 'b type that will be the output of your computation expression is, in this example, actually the tuple int * int, so you rewrite the predicate function to actually just take that 'b type, and then everything works:
let filterAndCollect (pred : 'b -> bool) (f : 'a -> 'b list) (m : 'a list) =
let f' a = [ for b in f a do if pred b then yield b ]
List.collect f' m
type FilteringListMonad(pred) =
member o.Bind( (m:'a list), (f: 'a -> 'b list) ) = filterAndCollect pred f m
member o.Return(x) = [x]
let filteredList = FilteringListMonad(fun (x:int,y:int) -> x < y)
let test2 =
filteredList {
let! x = [ 1 .. 10]
let! y = [2 .. 2 .. 20]
return (x,y)
}
Note that I also had to specify the types of the predicate function's inputs. Without that, F# was generalizing them to be "any type that implements System.IComparable, but I was passing in ints, which are value types and thus don't implement any interfaces. This led to the error
This expression was expected to have type 'System.IComparable' but here has type 'int'.
However, declaring both parameters to the predicate as int did the trick.
OP already accepted an answer, I will just provide a different approach which might be useful to help understand computation expressions in F#
One can extend computation expression with the useful ReturnFrom and Zero like so:
type ListMonad() =
member o.Bind (m, f) = List.collect f m
member o.Return x = [x]
member o.ReturnFrom l = l : _ list
member o.Zero () = []
let listM = ListMonad()
ReturnFrom allows us to return empty lists using return! [] as a result which enables filtering. Zero is a short-hand for this in that if the else branch isn't defined Zero is used.
This allows us to filter like so:
let test =
listM {
let! x = [ 1 .. 10]
let! y = [2 .. 2 .. 20]
if x % y = 0 then
return (x,y)
// By defining .Zero F# implicitly adds else branch if not defined
// else
// return! []
}
F# will expand the computation into something roughly like this:
let testEq =
[ 1 .. 10]
|> List.collect
(fun x ->
[2 .. 2 .. 20]
|> List.collect (fun y -> if x % y = 0 then [x,y] else [])
)
I have written a function that takes an array as input and returns an array of equal size as output. For example:
myFunc [| "apple"; "orange"; "banana" |]
> val it : (string * string) [] =
[|("red", "sphere"); ("orange", "sphere"); ("yellow", "oblong")|]
Now I want to assign the results via a let binding. For example:
let [|
( appleColor, appleShape );
( orangeColor, orangeShape );
( bananaColor, bananaShape )
|] =
myFunc [| "apple"; "orange"; "banana" |]
Which works great...
> val orangeShape : string = "sphere"
> val orangeColor : string = "orange"
> val bananaShape : string = "oblong"
> val bananaColor : string = "yellow"
> val appleShape : string = "sphere"
> val appleColor : string = "red"
...except it produces a warning:
warning FS0025: Incomplete pattern matches on this expression. For example, the value '[|_; _; _; _|]' may indicate a case not covered by the pattern(s).
The source and reason for the warning has already been covered, I'm just looking for a succinct work-around. This function call occurs near the top of my function, and I don't like the idea of putting the entire function body inside a match:
let otherFunc =
match myFunc [| "apple"; "orange"; "banana" |] with
| [|
( appleColor, appleShape );
( orangeColor, orangeShape );
( bananaColor, bananaShape )
|] ->
// ... the rest of my function logic
| _ -> failwith "Something impossible just happened!"
That just smells bad. I don't like the idea of ignoring the warning either - goes against my better judgment. Are there any other options open to me, or do I just need to find a different approach entirely?
One possibility if you expect this kind of calling pattern to be frequent is to make wrappers that act on the sizes of tuples you expect, e.g.
myFunc3 (in1,in2,in3) =
match myFunc [|in1;in2;in3|] with
[|out1;out2;out3|] -> out1, out2, out3
_ -> failwith "Internal error"
etc. But all it does is move the ugly code to a standard place, and writing out the wrappers will be inconvenient.
I don't think there's any better option with this API, because there's no way to tell the compiler that myFunc always returns the same number of elements it is passed.
Another option might be to replace myFunc with an IDisposable class:
type MyClass() =
let expensiveResource = ...
member this.MyFunc(v) = ...calculate something with v using expensiveResource
interface IDisposable with
override this.Dispose() = // cleanup resource
and then use it in a block like
use myClass = new MyClass()
let appleColor, appleShape = myClass.MyFunc(apple)
...
Adapting #Ganesh's answer, here's a primitive way to approach the problem:
let Tuple2Map f (u, v)
= (f u, f v)
let Tuple3Map f (u, v, w)
= (f u, f v, f w)
let Tuple4Map f (u, v, w, x)
= (f u, f v, f w, f x)
Example:
let Square x = x * x
let (a,b) = Tuple2Map Square (4,6)
// Output:
// val b : int = 36
// val a : int = 16
But I guess something even more primitive would be this:
let Square x = x * x
let (a,b) = (Square 4, Square 6)
And if the function name is too long, e.g.
// Really wordy way to assign to (a,b)
let FunctionWithLotsOfInput w x y z = w * x * y * z
let (a,b) =
(FunctionWithLotsOfInput input1 input2 input3 input4A,
FunctionWithLotsOfInput input1 input2 input3 input4B)
We can define temporary function
let FunctionWithLotsOfInput w x y z = w * x * y * z
// Partially applied function, temporary function
let (a,b) =
let f = (FunctionWithLotsOfInput input1 input2 input3)
(f input4A, f input4B)
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