This is not working...
I get error FS0001: The type 'string' is not compatible with the type 'seq'
for the last line. Why?
let rec Parse (charlist) =
match charlist with
| head :: tail -> printf "%s " head
Parse tail
| [] -> None
Parse (Seq.toList "this is a sentence.") |> ignore
The problem is that printf "%s " head means that head must be a string, but you actually want it to be a char, so you'll see that Parse has inferred type string list -> 'a option. Therefore, F# expects Seq.toList to be applied to a string seq, not a string.
The simple fix is to change the line doing the printing to printf "%c " head.
Related
I have a project using NLog and there is a wrapper around the logger, in order to turn logging off in some areas:
member this.SetQuiet q = quiet <- q
member this.Trace format = Printf.kprintf (fun s -> if not quiet then logger.Trace(s)) format
member this.Debug format = Printf.kprintf (fun s -> if not quiet then logger.Debug(s)) format
member this.Info format = Printf.kprintf (fun s -> if not quiet then logger.Info(s)) format
member this.Warn format = Printf.kprintf (fun s -> if not quiet then logger.Warn(s)) format
member this.Error format = Printf.kprintf (fun s -> if not quiet then logger.Error(s)) format
member this.Fatal format = Printf.kprintf (fun s -> if not quiet then logger.Fatal(s)) format
this works quite well, but I have an issue:
logger.Info "hello"
logger.Info <| "hello"
will work properly, whereas:
"hello" |> logger.Info
will not compile with this error:
typecheck error The type 'string' is not compatible with the type 'Printf.StringFormat<'a,string>'
can someone explain me why this fails? the order kprintf-continuation-format should still be respected here, no?
Is there a workaround for this? the reason is that I'm trying to do a 'tee' to log messages in a non verbose way (the tee just applies a function and then returns the original parameter):
"my messsage"
|> tee logger.Info
|> Result.Ok
That happens because printf and similar methods uses formatting. It allows type-safe usage of these method. For example printfn "%d" enforces integer as parameter
printfn "%d" 3
printfn "%d" 3.14 // error
printfn "%s %f" enforces string and float.
printfn "%s %f" "Hello" 3.14
printfn "%s %f" '3' 14 // error
This means that you should change methods this way (added "%s")
member this.Trace format = Printf.kprintf (fun s -> if not quiet then logger.Trace(s)) "%s" format
*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 -> ??
I'm writing a monadic parser using Alex and Happy in Haskell.
My error function is defined like this:
parseError :: Token -> Alex a
parseError _ = alexError "error occurred"
How can I send custom errors (like incorrect type while trying to add a string to a number) during parsing?
UPDATE
The parser doesn't need to do the type checking, I'm doing it inside the production since I keep track of the operands type.
As said in a comment, I cannot use the parseError, so is there a way to print an error and stop the parser?
I've solved it by implementing this function:
fatalError :: (Show a1, Show a) => [Char] -> a -> a1 -> t
fatalError s l c = error ("Error at line " ++ (show l) ++ " column " ++ (show c) ++ ": " ++ s)
and I call it from the production when an error is detected
I am going through the "Try F#" tutorial and decided that I wanted to try writing the code in the editor to Visual Studio once I installed the necessary F# plugins.
The code is:
let toHackerTalk (phrase:string) =
phrase.Replace("t", "7").Replace("o", "0")
let name:string = "tom"
printf "%s",toHackerTalk name
The code runs on the online editor, but when I try running it on Visual Studio all it does is flash the command prompt asking me to press a key to continue. I realize that this must be a very basic question, I just can't see what the problem could be since it runs perfectly fine in the online editor.
Your printf line should look like this:
printf "%s" (toHackerTalk name)
Otherwise, you are creating a tuple instead of calling printf.
you should do:
printf "%s" (toHackerTalk name)
see demo: https://dotnetfiddle.net/Ft9O4z
because with F# you dont need to separate function parameters with comma, comma is used for tuples:
let d = printf "%s",toHackerTalk name
printfn "%A" d // (<fun:d#6>, "70m")
you are creating a tuple with two values ( (printf "%s"), (toHackerTalk name) ):
printf "%s" // a function string -> unit
"70m" // a string
you dont get error because you are creating a tuple, who is ignored (maybe you get a warning asking to ignore value)
you cannot do
printf "%s" toHackerTalk name
because this mean call printf with 3 args:
"%s" a string
toHackerTalk a function string -> unit
name a string
and printf "%s" expect only 1 string arg
so you need to do
printf "%s" (toHackerTalk name) to execute toHackerTalk name and pass result as argument
is the same as
let temp = toHackerTalk name // or (toHackerTalk name) parens are optional
printf "%s" temp
I'm an F# noob. I'm trying to create a function to format a results tuple, where the last element may or may not exist - since it's intended to hold any exceptions that might been caught during processing.
let formatResults resultsTuple =
match resultsTuple with
|(name1, name2, diff, count, correlation, None) -> (sprintf "%A and %A with diff %A had %A pairs and showed a correlation coefficient of %A" name1 name2 diff count correlation)
|(name1, name2, diff, _, _, Some(ex)) -> (sprintf "Error: %A and %A with diff %A threw exception %A" name1, name2, diff, ex) |> sprintf "%A"
See in the last line how I had to pipe the results of the first sprintf into the second sprintf? Basically, it tells me I've got a syntax error somewhere, and that the program isn't doing what I think it is. (Preliminary testing seems to be giving reasonable output, but it makes me nervous.)
Why does that compile, but this doesn't? It gives me the compile error "This expression was expected to have type string but here has type 'a * 'b * 'c * 'd".
let formatResults resultsTuple =
match resultsTuple with
|(name1, name2, diff, count, correlation, None) -> sprintf "%A and %A with diff %A had %A pairs and showed a correlation coefficient of %A" name1 name2 diff count correlation
|(name1, name2, diff, _, _, Some(ex)) -> sprintf "Error: %A and %A with diff %A threw exception %A" name1, name2, diff, ex
sprintf "Error: %A and %A with diff %A threw exception %A" name1, name2, diff, ex
You're creating a tuple that contains the function returned by sprintf "..." name1 as its first element. The other elements of the tuple are name2, diff and ex. By passing that tuple to sprintf "%A", you're turning it into a string, making the types work. But of course that still won't make it do what you want.
To do what you want, get rid of the commas.