I have the following line:
| ResponseTableTypes.Order ->
orderProcessor.ProcessEvent action message
orderEvent.Trigger()
since I have a lot of entries, for layout reasons, I did:
| ResponseTableTypes.Order -> orderProcessor.ProcessEvent action message; orderEvent.Trigger()
all good, but then I added some return type:
| ResponseTableTypes.Order -> let s = orderProcessor.ProcessEvent action message; orderEvent.Trigger(s)
that will not compile, I get:
The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.
so, if I break down the line again:
| ResponseTableTypes.Order ->
let s = orderProcessor.ProcessEvent action message
orderEvent.Trigger(s)
then it obviously works again
what is happening with the let/semicolon combination?
I will answer your question, but in doing so answer a more important question of how to ask a question.
Starting with | ResponseTableTypes.Order -> let s = orderProcessor.ProcessEvent action message; orderEvent.Trigger(s), let's reduce irrelevancies such as tables, orders, and events:
let result =
let s = expression; action
Now let's ascribe simple values to the names, so that apart from the issue we want to identify, it should compile.
let x =
let y = 0; 0
// FS0588 the block following this let is unfinished.
// FS0020 The result of this expression has type 'int' and is implicitly ignored.
Now that we have a clean question, we can start to answer it, but this is the easy part. let y = 0; 0 is equivalent to let y = (0;0) and so the first 0 is being ignored, and since let y = ... is an incomplete expression which does not return anything, there is nothing to ascribe to x.
There is an antique syntax let y = 0 in 0 which does allow merging multiple lines with lets into one.
I am a newbie in F# and have been following guides to try to make a piece of code work but it hasn't.
I create types of single and coop sports through inheritance.
Then I use pattern matching to know the type and, if it is a coop sport, get also the number of players. Then rank each accordingly.
However, I have been getting errors. I followed Microsoft examples on this and I don't really understand the errors. I don't have a functional programming background.
type Sport (name: string) =
member x.Name = name
type Individual(name: string) =
inherit Sport(name)
type Team(name: string, numberOfPlayers : int) =
inherit Sport(name)
member x.numberOfPlayers = numberOfPlayers
let MK = new Individual("Combate Mortal")
let SF = new Individual("Lutadores de Rua")
let Tk = new Individual("Tekken Chupa")
let MvC = new Team("Marvel Contra Capcom", 3)
let Dbz = new Team("Bolas do Dragao", 3)
let interpretSport (sport:string) (players:int) =
match sport with
| "Combate Mortal" -> printfn "Rank1"
| "Lutadores de Rua" -> printfn "Rank2"
| "Tekken Chupa" -> printfn "Rank3"
| "Bolas do Dragao" -> printfn "Rank4. No of players: %d " players
| "Marvel Contra Capcom" -> printfn "Rank5. No of players: %d" players
| _ -> printfn "not a sport in our list..."
let matchSport (sport:Sport) =
match sport with
| :? Individual -> interpretSport(sport.Name)
| :? Team as teamSport -> interpretSport(teamSport.Name,teamSport.numberOfPlayers)
| _ -> printfn "not a sport"
matchSport(MK)
matchSport(SF)
matchSport(Tk)
matchSport(MvC)
matchSport(Dbz)
1st error when calling function with more than 1 argument:
2nd error when printing:
The question has already been answered, but because the asker says he is a newby in F#, maybe it's worth to iterate a little.
To begin, you define a function with two parameters:
let interpreteSport (sport:string) (player:int) =
In F#, there is no notion of optional parameters in the same sense that they exist in C#, so if you declare a function with two parameters, and you want to invoke it, and get its return value, you must supply all the parameters you put in its definition.
So in the first branch of your match expression, when you write:
:? Individual -> interpretSport(sport.Name)
you are making an error, passing only one parameter to a function that takes two.
But wait! Why the compiler don't alert you with an error saying you are calling a function with one parameter when it expects two?
Because it turns out that what you write, even if it does not call the interpreteSport function as you believed, it's a perfect valid expression in F#.
What it returns is an expression called "partially applied function", that is, a function that has received its first parameter, and is waiting for another one.
If you assign the result of such an expression to a value, let's say:
let parzFun = interpretSport sport.Name
you can then pass this value around in your code and, when you are ready to supply the missing parameter, evaluate it like this:
let result = parzFun 1
That's what the compiler is telling you when it talks about 'int -> unit': function signatures in F# are given in this form:
a -> b -> c -> d -> retval, where a, b, c, d etc. are the types of the parameters, and retVal the return value.
Your interpreteSport function has a signature of: string -> int -> unit, where unit is the special type that means 'no value', similar to C# void, but with the big difference that unit is an expression that you can correctly assign to a value, while void is just a keyword, and you cannot assign a variable to void in C#.
OK, so, when you call your function passing only the first parameter (a string), what you obtain is an expression of type int -> unit, that is another function that expects and integer and returns unit.
Because this expression is in a branch of a match expression, and because all the branches of a match expression must return the same type, the other 2 branches are also expected to return an int -> unit function, what it's not, and that explain your second error.
More on this in a moment, but before, we must look at the first error reported by the compiler, caused by this line of code:
:? Team as teamSport -> interpretSport(teamSport.Name,teamSport.numberOfPlayers)
Here, you are thinking your are calling your function with 2 parameters, but your are actually not: when you put 2 values in parenthesis, separated by a comma, you are creating a tuple, that is, a single value composed of two or more values. It's like your are passing again only the first parameter, but now with the wrong type: the first parameter of you function is a string, and you are instead passing a tuple: ('a * 'b) is how F# represents tuples: that means a single value composed of a value of type 'a (generic, in your case string) and another of type 'b (generic, in your case integer).
To call your function correctly you must call it so:
:? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
But even if you limit yourself to this correction you will have all the same the second error because, remember, the first expression of your match returns a partially applied funcion, so int -> unit (a function that expects an integer and returns a unit) while your second and your third expressions are now of type unit, because they actually call two functions that return unit (interpreteSport and printfn). To completely fix your code, as has already been said in other answers, you must supply the missing integer parameter to the first call, so:
let matchSport (sport:Sport) =
match sport with
| :? Individual -> interpretSport sport.Name 1
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
| _ -> printfn "not a sport"
If this is a F# learning exercise then it's best to avoid classes and inheritance completely. The fundamental idiomatic F# types are records and discriminated unions.
The intent of your code is not clear to me at all, but I have attempted to refactor to remove the use of classes:
type Players =
| Individual
| Team of numberOfPlayers:int
type Sport = { Name : string; Players : Players }
let MK = { Name = "Combate Mortal"; Players = Individual }
let SF = { Name = "Lutadores de Rua"; Players = Individual }
let Tk = { Name = "Tekken Chupa"; Players = Individual }
let MvC = { Name = "Marvel Contra Capcom"; Players = Team 3 }
let Dbz = { Name = "Bolas do Dragao"; Players = Team 3 }
let interpretSport (sport:Sport) =
let players =
match sport.Players with
| Individual -> ""
| Team numberOfPlayers -> sprintf ". No of players: %d" numberOfPlayers
let rank =
match sport.Name with
| "Combate Mortal" -> Some 1
| "Lutadores de Rua" -> Some 2
| "Tekken Chupa" -> Some 3
| "Bolas do Dragao" -> Some 4
| "Marvel Contra Capcom" -> Some 5
| _ -> None
match rank with
| Some r -> printfn "Rank%d%s" r players
| None -> printfn "not a sport in our list..."
Your function interpretSport has two arguments but your first call to it has only one. Try calling it like so:
| :? Individual -> interpretSport sport.Name 1
Also, the second call uses tupled parameters but the function is declared to take curried parameters. Try calling it like so:
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
There are several small problems with your code. The most obvious is in matchSport, you are calling interpretSport in an uncurried style, with an argument tuple. The call should look like:
Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
However, that's a problem, because on the first case of the pattern matching you call interpretSport with only one argument, so you partially apply it and you get a type int -> unit, but when you fully apply it on the second case you get unit, and of course all types of the pattern matching cases must match. The cheapest solution would be to add a 1 to your call on the first case like this:
Individual -> interpretSport sport.Name 1
But you probably want to use the sports you bound before (maybe in a list you give as a parameter) to do the checking. It is in general a bad idea (in functional programming and elsewhere) to hard-code that many strings, you probably want to do some kind of association List, or Map of the Sports to the Ranks, then fold over the sports List and match when found with individual or team and then print whatever the Map gives you for that case. This would be shorter and more extensible.
My code :
let main _ =
let t = (System.Console.In.ReadLine ()) |> int
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int
0
And I got errors as following :
The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.
Can you help me ? Thank you very much .
To give some more details on why this is required - in F#, everything (aside from type and module definitions) is expression that has some return value. This even applies to things like printf - they still return value, but it is the unit value, written as (), which represents a dummy value with no information.
The problem is that let <var> = <expr> is not a complete expression, because it does not return anything. The full form is let <var> = <expr1> in <expr2>. This assigns the result of <expr1> to the variable <var> and evaluates <expr2> and returns the result. If you're using a line break, you can omit in, but you still need some body.
In yor example, the best option is to use () as the body, because you're not returning anything useful. You can write this using in or using a line break:
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int in ()
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int
()
This is not very useful thing to write, because you're not using n anywhere, but that's another question.
Inside your for loop, the last statement is a let. Adding a 0 indented to the same level should fix the problem
Thanks John Palmer . I learned many things . So this's result for the problem :
let t = (System.Console.In.ReadLine ()) |> int
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int
printf("%d\n") n
0
0
I am new to programming in functional languages. I am attempting to implement the F# tryFindIndex function.
let rec tryFindIndex func list =
match list with
| [] -> None
| hd::tl -> if func hd then Some(0)
else (tryFindIndex func tl) + 1
The issue is with the last line, since adding 1 causes the return type to be 'int' instead of 'int option'. I need to track the index recursively.
Pass the index as an additional parameter. If you don't do this, then your function also isn't tail recursive. Also implement your recursion as a separate loop to hide the index parameter.
let tryFindIndex func list =
let rec loop func list index =
match list with
| [] -> None
| hd::tl -> if func hd then Some(index)
else loop func tl (index+1)
loop func list 0
As John noted in the comments, the core library implementation of that looks like this:
let tryFindIndex f list =
let rec loop n = function[] -> None | h::t -> if f h then Some n else loop (n+1) t
loop 0 list
I have the following code to return a record from a list of records that has a field with value equal to Accountnumber.
lookup(AccountNumber, [#account{no=AccountNumber} = Rec | _]) ->
Rec;
lookup(AccountNumber, [_| T]) ->
lookup(AccountNumber, T);
lookup(AccountNumber, []) ->
not_found.
The above code works fine, but when I try to convert it to filter using the following code:
lookup(AccountNumber, DBRef) ->
lists:filter(fun(#account{no=AccountNumber} = Rec) -> Rec end, DBRef).
I got the following error:
** exception error: no case clause matching #account{no = 2,balance = 0,pin = undefined,name = "Ali",
transactions = []}
in function lists:'-filter/2-lc$^0/1-0-'/2 (lists.erl, line 1271)
What is the reason for the error?
There are multiple problems in the code
1.The filter should always return atom true or false for all list elements. This is causing you the error.
2.When the variable outside the fun block is used in fun header, they are not patterned matched, the variable outside is masked. Hence the pattern match fails.
You can see the modified code below.
lookup(AccountNumber, DBRef) ->
lists:filter(
fun(#account{no=AccNo}) when AccNo =:= AccountNumber -> true;
(_) -> false
end, DBRef).