FAKE CscHelper: Csc vs csc? - f#

I don't understand the difference between these two.
I want to compile a single c# file into a dll using FAKE's CscHelper. This is my build file:
// include Fake lib
#r #"packages/FAKE/tools/FakeLib.dll"
open Fake
open CscHelper
Target "Default" (fun _ ->
["Discover.cs"] |> csc (fun p -> { p with Output="Discover.dll"; Target=Library })
)
RunTargetOrDefault "Default"
This is the error I get:
build.fsx(7,24): error FS0001: Type mismatch. Expecting a
string list -> unit
but given a
string list -> int
The type 'unit' does not match the type 'int'
If I replace "csc" with "Csc" it compiles correctly. Why? In the documentation the code samples are literally identical other than that single character. The method signatures appear the same other than return type. Why are there two variants and how do you make the lowercase one work?

The lower case form is proper. You can always pipe the results to the ignore function to be sure to return a unit ().
// include Fake lib
#r #"packages/FAKE/tools/FakeLib.dll"
open Fake
open CscHelper
Target "Default" (fun _ ->
["Discover.cs"] |> csc (fun p -> { p with Output="Discover.dll"; Target=Library }) |> ignore
)
RunTargetOrDefault "Default"
The actual tool tip tells you what is going on (it returns exit status code which is of type int):
Type mismatch. Expecting a
'string list -> unit'
but given a
'string list -> int'
The type 'unit' does not match the type 'int'
val csc : setParams:(CscParams -> CscParams) -> inputFiles:string list -> int
Full name: Fake.CscHelper.csc
Compiles the given C# source files with the specified parameters.
Parameters
setParams - Function used to overwrite the default CSC parameters.
inputFiles - The C# input files.
Returns
The exit status code of the compile process.
Sample
["file1.cs"; "file2.cs"] |> csc (fun parameters -> { parameters with Output = ... Target = ... ... })
You may have already found this out or not, but it is good that everyone knows there are options. Thank you. Good day.

Related

In F#, how to fix a pattern match error with value type "a->'b->Model'

(I'm new to F#). I have the following definitions in F#:
init i j =
{ Id = Guid.NewGuid ()
InnerRows = [0 .. 2] |> List.map (Cell.init i j)
SelectedInnerRow = None}
let update msg m =
match msg with
| Select id -> { m with SelectedInnerRow = id }
| Reset -> init
where the update function shows the following error on "Reset -> init":
All branches of a pattern match expression must return values of the same type as the first branch, where here is 'Model'. This branch returns a value of type ''a -> 'b -> Model'
What does ''a -> 'b -> Model' mean, and how can this be fixed?
Thank you.
TIA
As the error message says: All branches of a pattern match must return values of the same type
Your Select id -> ... branch returns a value of type Model
Your Result -> init branch returns the function init, which has type 'a -> 'b -> Model - that is, it takes two arguments of some types 'a and 'b and returns a Model.
The types don't match. Different types. See?
From the semantics, I am guessing that what you really want your update function to return is Model. If so, you need to give the init function its two arguments, so that it returns you a Model, and that can be the result of the second branch of the pattern-match expression:
| Result -> init 0 0
NOTE: I'm not actually sure that 0 0 are correct arguments in this case, I'm just guessing. There is no way to know what they should be without knowing what Cell.init i j does and what type of arguments it expects.
You have to figure out what the actual arguments init needs here and pass them in.

Why does F# not like the type ('a list list) as input?

*I edited my original post to include more info.
I'm working on an F# assignment where I'm supposed to create a function that takes an "any list list" as input and outputs an "any list". It should be able to concatenate a list of lists into a single list.
Here's what my function looks like:
let llst = [ [1] ; [2;3] ; ['d';'e';'f'] ]
let concat (llst:'a list list) : 'a list =
List.concat llst
List.iter (fun elem -> printf "%d " elem) concat
This solution more or less copied directly from microsofts example of using the List.concat function, the only exception being the specification of input/output types.
When i run the code i get this error:
concat.fsx(7,43): error FS0001: This expression was expected to have type
''a list'
but here has type
''b list list -> 'b list'
So it appears that concat is turning my llst into a character list, which i don't understand.
Can anyone help me understand why I'm getting this type error and how I can write a function that takes the types that I need?
The problem is somewhere in your implementation of the concat function. It is hard to say where exactly without seeing your code, but since this is an assignment, it is actually perhaps better to explain what the error message is telling you, so that you can find the issue yourself.
The error message is telling you that the F# type inference algorithm found a place in your code where the actual type of what you wrote does not match the type that is expected in that location. It also tells you what the two mismatching types are. For example, say you write something like this:
let concat (llst:'a list list) : 'a list =
llst
You will get the error you are getting on the second line, because the type of llst is 'a list list (the compiler knows this from the type annotation you give on line 1), but the expected type is the same as the result type of the function which is 'a list - also specified by your type annotation.
So, to help you find the issue - look at the exact place where you are getting an error and try to infer why compiler thinks that the actual type is 'a list list and try to understand why it expects 'a list as the type that should be in this place.
This is correct:
let concat (llst:'a list list) : 'a list =
List.concat llst
However, it's really equivalent to let concat = List.concat
This, however, doesn't compile, the elements of the lists need to be of the same type:
let llst = [ [1] ; [2;3] ; ['d';'e';'f'] ]
This also is problematic:
List.iter (fun elem -> printf "%d " elem) concat
List.iter has two arguments and the second one needs to be a List. However in your case you are (as per compiler error) providing your concat function which is a a' List List -> a' List.
What I suspect you meant to do, is apply the concat function to your llist first:
List.iter (fun elem -> printf "%d " elem) (concat llist)
// or
llist
|> concat
|> List.iter (fun elem -> printf "%d " elem)
However, all of this is perhaps missing the point of the exercise. What perhaps you need to do is implement some simple recursion based on the empty / non-empty state of your list, ie. fill in the blanks from here:
let rec myconcat acc inlist =
match inlist with
| [] -> ??
| elt :: tail -> ??

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.

F# mysterious differences between piping and function application

Premise: I thought that the piping operator is nothing but syntactic sugar, thus x |> f should be exactly the same as f(x).
Analogously, I thought that f (fun x -> foo) is equivalent to let g = fun x -> foo; f g
But apparently there are differences that I do not understand.
Example 1:
static member contents =
let files = Directory.EnumerateFiles (__SOURCE_DIRECTORY__+ #"\foo\bar.txt")
let fileList = List.ofSeq files
fileList |> List.map (fun f -> TestCaseData(f).SetName(""))
This works fine: TestCaseData expects an arg:obj which is matched by f which in turn in inferred to be a string since fileList is a list of file names.
However the following does not work
static member contents =
let files = Directory.EnumerateFiles (__SOURCE_DIRECTORY__+ #"\foo\bar.txt")
let fileList = List.ofSeq files
List.map (fun f -> TestCaseData(f).SetName("")) fileList
Nothing but the last line has changed. Suddenly f is inferred as obj [] and TestCaseData requires an argument of type obj [] and hence I get an error
Error 1 Type mismatch. Expecting a obj [] list but given a string list
The type 'obj []' does not match the type 'string'
I would have thought that both snippets are equivalent in produce correct code but only the first does?!
Example 2:
[<TestCase("nonsense", TestName="Nonsense")>]
member x.InvalidInputs str =
let lexbuf = Microsoft.FSharp.Text.Lexing.LexBuffer<char>.FromString(str)
Assert.Throws<FatalError> (fun () -> ParsePkg.parse "Dummy path" lexbuf |> ignore)
|> ignore
Above everything works fine.
[<TestCase("nonsense", TestName="Nonsense")>]
member x.InvalidInputs str =
let lexbuf = Microsoft.FSharp.Text.Lexing.LexBuffer<char>.FromString(str)
let ff = fun () -> ParsePkg.parse "Dummy path" lexbuf |> ignore
Assert.Throws<FatalError> (ff)
|> ignore
As you see, all I did was pull out the argument of the assertion by first defining let ff = ... (for readability reasons, say) and suddenly the compiler points to the (ff) argument and complains:
Error 2 This expression was expected to have type TestDelegate but here has type unit -> unit
TestDelegate is a type of NUnit that I am using here and it happens to coincide with unit->unit so I'd assume it would be unified anyway but that does not even matter. Why at all is it possible that the type changes, since again I believe to have done a purely syntactic replacement?!
type inferences is done sequential top to bottom. So in the first case fileList is the first lexical argument.
The information that the fileList is a list of strings is then used in the piping expression. To know whether stringis a legal type for f the signature of TestCaseData is used. As commented, based on the error message TestCaseData probably accepts [<Params>] obj [] making a single string argument valid.
In the second version there's no information to use when determining the type of f other than the signature of TestCaseData and therefor f is inferred to be of type obj []
Similar is true in the other example. Just the other way around. Pulling out the function removes the information that it's supposed to be of type TestDelegate.
At the lexical point the only information available is that it's a function of type unit->unit.
When the function is used at a program point where a TestDelegate is required. The type inference tests whether the function can be used as a TestDelegate and if so, infers the type to be TestDelegate

Attempt to convert object to generic type results with FS0013 error

I am trying to cast obj to 'T and I receive FS0013 error in compile time.
What is wrong with my code?
Maybe it is broken because I tried to "map" it from C# and this is done in completely different way in F#?
let myFunc (x : Option<'T>) =
match x with
None -> failwith "wtf"
| Some x -> Convert.ChangeType(x, typedefof<'T>) :> 'T
Full error text:
error FS0013: The static coercion from type
obj
to
'T
involves an indeterminate type based on information prior to this program point. Static coercions are not allowed on some types. Further type annotations are needed.
UPDATE:
This is the actual function I am trying to write. Option's value is used in case I don't have my own value.
let ( %? ) (defaultValue : Option<'a>) (parameterName : string)
= match (environVar parameterName) with
null -> match defaultValue with
None -> failwith "No value found as well as default value is not set"
| Some defaultVal -> defaultVal
| x -> let objectResult = Convert.ChangeType(x, typedefof<'a>)
objectResult :> 'a
You don't need to convert !
Just write:
| Some x -> x
Then your function is generic.
The pattern match has already decomposed the type and unwrapped the value from the option.
Don't confuse obj with generic 'T.
A function returning an obj is not necessarily generic.
EDIT
After your update, you can use this:
objectResult :?> 'a
But you will have no run-time guaranties.
In F# :> means 'upcast' and :?> means 'downcast' (if you can). The former has compile-time checking that's why 'cast' is split in 2 different operations.

Resources