Reputation: 142987
I am writing an application to replace our technical support department. When a customer needs technical support, we will simply mail him a floppy disk containing this application, which he can simply put into his computer hole and install it. They just type in their problem and the program will output the solution.
I tried writing it in F#, but F# doesn't like it. I wrote this simple recursive function that shows a greeting message to the customer, but F# tells me "no, this code is bad". I'm quite confident that my code is good, and can't figure out why F# thinks it's so bad.
This is my code:
open System
let rec GreetCustomer message =
let DisplayMessage message =
Console.WriteLine(message + " " : string) |> ignore
GreetCustomer
DisplayMessage(x)
Console.WriteLine("Please do the needful by telling us your name?");
let CustomerName = Console.ReadLine()
GreetCustomer("Hello,")(CustomerName)("!")("How")("to")("help")("you")("today?")
and F# tells me
Type mismatch. Expecting a 'a but given a 'b -> 'a The resulting type would be infinite when unifying ''a' and ''b -> 'a'
Of course the resulting type is infinite. I want to be able to chain the method calls up to an infinite number of times. I don't understand why F# doesn't like infinite types; I can write the same program in Javascript without any issues:
GreetCustomer = function(message) {
DisplayMessage = function(message) {
document.write(message + " ");
return GreetCustomer;
};
return DisplayMessage(message);
};
CustomerName = prompt("Please do the needful by telling us your name?");
GreetCustomer("Hello,")(CustomerName)("!")("How")("to")("help")("you")("today?");
and it has exactly the output I want:
Hello, Peter ! How to help you today?
If it works in Javascript, surely there must be a way to do it in F#.
How can I fix my F# program so that it won't complain about infinite types?
Upvotes: 0
Views: 469
Reputation: 47914
The question I linked in the comments elaborates on this extensively. There are ways to do this in F#, but none will give you the syntax you want. The following answers are about as good as it gets.
https://stackoverflow.com/questions/2679547/function-which-returns-itself/2684005#2684005
https://stackoverflow.com/questions/2679547/function-which-returns-itself/2679578#2679578
In short, this is a limitation of type inference. As the compiler complains, the type of a function which returns itself cannot be solved; it's infinite.
This is my preferred workaround (combining answers from the question I linked):
type Inf<'T> = delegate of 'T -> Inf<'T>
let rec makeInfinite f =
fun x ->
f x |> ignore
Inf(makeInfinite f)
let (+>) (inf:Inf<_>) arg = inf.Invoke(arg)
let GreetCustomer = makeInfinite (printf "%s")
GreetCustomer "Hello " +> "there, " +> "how " +> "are " +> "you?" |> ignore
Upvotes: 4
Reputation: 55195
The answers that Daniel linked to should tell you how to work around the problem.
In principle, I think that it would be possible for F# to infer a type such as ('b -> 'a) as 'a
given your definition (which isn't valid F# syntax). The related language OCaml provides a -rectypes option to allow the compiler to infer cyclic definitions like this, but as I understand it the flag isn't enabled by default because inferred cyclic types are almost always an indication that the programmer has made a mistake.
Upvotes: 2