In Visual Studio 2015:
let myFunction (``string`` : string) =
"\"Quoted string\"" |> (Regex "\"[^\"]*\"").Match |> string
let myOtherFunction (str : string) =
"\"Quoted string\"" |> (Regex "\"[^\"]*\"").Match |> string
First function generates a compiler error, the string function is underlined in red. ("This expression was expected to have type Match -> 'a but here has type string")
Second function is fine, no problems.
Is this by design?
The reason is, your parameter and the call at the end are the same thing. Double backticks are used to escape the name, they are not part of the name.
So in your case that means that ``string`` and string are exactly the same thing, you are trying to pipe into your string parameter. And yes, this is totally by design.
The C# equivalent are #-escaped names, where for example #hello and hello would clash.
Related
I am trying to develop F# type provider.
It provides some DTOs (with the structure described in some external document) and a set of methods for processing them. The processing algorithm is based on reflection, and I want to have a single quotation representing it.
Generally, this algorithm must pass all method call arguments to the already written function serialize: obj -> MySerializationFormat, storing all results in a list, so I getting a value of MySerializationFormat list.
Code sample below shows, how I tried to do that for first time:
let serialize (value: obj) = ...
let processingCode: Expr list -> Expr =
fun args ->
let serializeArgExpr (arg: Expr) = <# serialize %%arg} #>
let argsExprs = List.map serializeArgExpr args
let serializedArgList =
List.foldBack (fun head tail -> <# (%head) :: (%tail)#>) argsExprs <# [] #>
// futher processing
At that point I faced with exception: In function serializeArgExpr the actual type of value in arg: Expr may vary, it can be some primitive type (e.g string, int, float), or some provided type. The problem is %% operator treats that arg as an expression of the obj type. Type check is performed on that line in Microsoft.FSharp.Quotations.Patterns module, in function fillHolesInRawExpr.
So, as the actual type of my term not matched the treated type for "hole" in the quotation, it throws invalidArg.
I have tried several technics to avoid these exceptions with casting operations in my quotation, but they don't work. Then I found Expr.Coerce(source, target) function, which looks like solving my problem. I have changed the code of serializeArgExpr to something like that:
let serializeArgExpr (arg: Expr) =
let value' = Expr.Coerce(value, typeof<obj>)
<# serialize %%value' } #>
Then faced a new strange exception:
The design-time type (point to a code line that uses my processingCode) utilized by a type provider was not found in the target reference assembly set
For me, it seems that my problem is to cast the type of value in any input Expr to an obj type. Thank you for diving in and trying to help.
I am learning F# but I just don't understand how I am supposed to use ToString. Below are a few attempts. The syntax errors are saying it is expecting type string but that it is actually type uint -> string. So it doens't actually appear to be invoking a function? Could this be explained? This seems like such a simple thing to do but I can't figure it out.
open System
open System.IO
open FSharp.Data
[<EntryPoint>]
let main (args: string[]) =
let htmlPage = HtmlDocument.Load("https://scrapethissite.com/")
printfn "%s" htmlPage.ToString // This causes a syntax error
htmlPage.ToString
|> (fun x -> printfn "%s" x) // This also causes a syntax error
0
.ToString is a method, not a value. In F# every method and every function has a parameter. In fact, that's how functions differ from values (and methods from properties): by having a parameter.
Unlike in C#, F# methods and functions cannot be parameterless. If there is nothing meaningful that you'd want to pass to the method, that method would still have one parameter of type unit. See how this is visible in the error message? unit -> string is the type.
To call such method, you have to pass it the parameter. The sole value of type unit is denoted (). So to call the method you should do:
htmlPage.ToString ()
|> printfn "%s"
Your first example is a bit more complicated. The following would not work:
printfn "%s" htmlPage.ToString ()
Why? Because according to F# syntax this looks like calling printfn and passing it three parameters: first "%s", then htmlPage.ToString, and finally (). To get the correct order of calls you have to use parentheses:
printfn "%s" (htmlPage.ToString ())
And finally, general piece of advice: when possible try to avoid methods and classes in F# code. Most things can be done with functions. In this particular case, the ToString methods can be replaced with the equivalent function string:
printfn "%s" (string htmlPage)
I am trying to use the pipe3 function from the FParsec library but I get an error I don't know how to solve.
Given the Record
type Point = { x: float; y: float }
and the following parser
let plistoffloats' =
pipe3 pfloat (pchar ',' .>> spaces) pfloat
(fun first z second -> { x = first; y = second })
What I try to achieve is a parser that receives a string in format "1.1, 3.7" and returns a Point
run plistoffloats' "1.1, 3.7"
Input : "1.1, 3.7"
Desired output : Point = {x = 1.1; y = 3.7;}
Error :
error FS0030: Value restriction. The value 'plistoffloats'' has been inferred to have generic type
val plistoffloats' : Parser <Point,'__a>
Either make the arguments to 'plistoffloats'' explicit or, if you do not intend for it to be generic, add a type annotation.
A simpler example with pchar also didn't work.
let parsesA = pchar 'a'
error FS0030: Value restriction. The value 'parsesA' has been inferred to have generic type
val parsesA : Parser<char,'_a>
Either make the arguments to 'parsesA' explicit or, if you do not intend for it to be generic, add a type annotation.
This is covered in the FParsec documentation; it will happen with any parser. The reason is because in the .Net type system, functions are allowed to be generic, but values are not — and in FParsec, you're generally defining parsers as values (e.g., you're typically writing let psomething = ... where psomething takes no parameters). Read the linked documentation page for the whole explanation — I won't copy and paste the whole thing — but the short version is that you can do one of two things:
Create a test function that looks like the following, and make sure it's used within the same source file on your parser:
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
Annotate your parser with a type annotation like the following:
type UserState = unit // You might change this later
let plistoffloats' : Parser<_, UserState> =
// ...
It sounds like you're trying to do #1, but unless your parser is called with test plistoffloats' in the same source file, the F# type inference won't be able to infer your user state type and will give you that error.
P.S. You can read more about the F# value restriction error here: Understanding F# Value Restriction Errors
P.P.S. The _ in the first position of Parser<_, UserState> does not mean "This type could be anything" the way _ means in other contexts like pattern matching. Instead, _ in a type annotation means "Please infer this type for me so that I don't have to specify it explicitly". In FParsec contexts, this is very useful because all your parsers will have UserState as their second type argument, but will have a varying type for the first type argument. And since the first type argument is the one that the type inference can infer, it means that you can copy and paste the type Parser<_, UserState> to all your parsers and F# will Do The Right Thing™ in each case.
I was attempting to convert this to F# but I can't figure out what I'm doing wrong as the error message (in title) is too broad of an error to search for, so I found no resolutions.
Here is the code:
let getIP : string =
let host = Dns.GetHostEntry(Dns.GetHostName())
for ip in host.AddressList do
if ip.AddressFamily = AddressFamily.InterNetwork then
ip.ToString() // big fat red underline here
"?"
A for loop in F# is for running imperative-style code, where the code inside the for loop does not produce a result but instead runs some kind of side-effect. Therefore, the expression block in an F# for loop is expected to produce the type unit, which is what side-effect functions should return. (E.g., printfn "Something" returns the unit type). Also, there's no way to exit a for loop early in F#; this is by design, and is another reason why a for loop isn't the best approach to do what you're trying to do.
What you're trying to do is go through a list one item at a time, find the first item that matches some condition, and return that item (and, if the item is not found, return some default value). F# has a specialized function for that: Seq.find (or List.find if host.AddressList is an F# list, or Array.find if host.AddressList is an array. Those three functions take different input types but all work the same way conceptually, so from now on I'll focus on Seq.find, which takes any IEnumerable as input so is most likely to be what you need here).
If you look at the Seq.find function's type signature in the F# docs, you'll see that it is:
('T -> bool) -> seq<'T> -> 'T
This means that the function takes two parameters, a 'T -> bool and seq<'T> and returns a 'T. The 'T syntax means "this is a generic type called T": in F#, the apostrophe means that what follows is the name of a generic type. The type 'T -> bool means a function that takes a 'T and returns a Boolean; i.e., a predicate that says "Yes, this matches what I'm looking for" or "No, keep looking". The second argument to Seq.find is a seq<'T>; seq is F#'s shorter name for an IEnumerable, so you can read this as IEnumerable<'T>. And the result is an item of type 'T.
Just from that function signature and name alone, you can guess what this does: it goes through the sequence of items and calls the predicate for each one; the first item for which the predicate returns true will be returned as the result of Seq.find.
But wait! What if the item you're looking for isn't in the sequence at all? Then Seq.find will throw an exception, which may not be the behavior you're looking for. Which is why the Seq.tryFind function exists: its function signature looks just like Seq.find, except for the return value: it returns 'T option rather than 'T. That means that you'll either get a result like Some "ip address" or None. In your case, you intend to return "?" if the item isn't found. So you want to convert a value that's either Some "ip address or None to either "ip address" (without the Some) or "?". That is what the defaultArg function is for: it takes a 'T option, and a 'T representing the default value to return if your value is None, and it returns a plain 'T.
So to sum up:
Seq.tryFind takes a predicate function and a sequence, and returns a 'T option. In your case, this will be a string option
defaultArg takes a 'T option and a default value, and returns a normal 'T (in your case, a string).
With these two pieces, plus a predicate function you can write yourself, we can do what you're looking for.
One more note before I show you the code: you wrote let getIP : string = (code). It seems like you intended for getIP to be a function, but you didn't give it any parameters. Writing let something = (code block) will create a value by running the code block immediately (and just once) and then assigning its result to the name something. Whereas writing let something() = (code block) will create a function. It will not run the code block immediately, but it will instead run the code block every time the function is called. So I think you should have written let getIP() : string = (code).
Okay, so having explained all that, let's put this together to give you a getIP function that actually works:
let getIP() = // No need to declare the return type, since F# can infer it
let isInternet ip = // This is the predicate function
// Note that this function isn't accessible outside of getIP()
ip.AddressFamily = AddressFamily.InterNetwork
let host = Dns.GetHostEntry(Dns.GetHostName())
let maybeIP = Seq.tryFind isInternet host.AddressList
defaultArg maybeIP "?"
I hope that's clear enough; if there's anything you don't understand, let me know and I'll try to explain further.
Edit: The above has one possible flaw: the fact that F# may not be able to infer the type of the ip argument in isInternet without an explicit type declaration. It's clear from the code that it needs to be some class with an .AddressFamily property, but the F# compiler can't know (at this point in the code) which class you intend to pass to this predicate function. That's because the F# compiler is a single-pass compiler, that works its way through the code in a top-down, left-to-right order. To be able to infer the type of the ip parameter, you might need to rearrange the code a little, as follows:
let getIP() = // No need to declare the return type, since F# can infer it
let host = Dns.GetHostEntry(Dns.GetHostName())
let maybeIP = host.AddressList |> Seq.tryFind (fun ip -> ip.AddressFamily = AddressFamily.InterNetwork)
defaultArg maybeIP "?"
This is actually more idiomatic F# anyway. When you have a predicate function being passed to Seq.tryFind or other similar functions, the most common style in F# is to declare that predicate as an anonymous function using the fun keyword; this works just like lambdas in C# (in C# that predicate would be ip => ip.AddressFamily == AddressFamily.InterNetwork). And the other thing that's common is to use the |> operator with things like Seq.tryFind and others that take predicates. The |> operator basically* takes the value that's before the |> operator and passes it as the last parameter of the function that's after the operator. So foo |> Seq.tryFind (fun x -> xyz) is just like writing Seq.tryFind (fun x -> xyz) foo, except that foo is the first thing you read in that line. And since foo is the sequence that you're looking in, and fun x -> xyz is how you're looking, that feels more natural: in English, you'd say "Please look in my closet for a green shirt", so the concept "closet" comes up before "green shirt". And in idiomatic F#, you'd write closet |> Seq.find (fun shirt -> shirt.Color = "green"): again, the concept "closet" comes up before "green shirt".
With this version of the function, F# will encounter host.AddressList before it encounters fun ip -> ..., so it will know that the name ip refers to one item in host.AddressList. And since it knows the type of host.AddressList, it will be able to infer the type of ip.
* There's a lot more going on behind the scenes with the |> operator, involving currying and partial application. But at a beginner level, just think of it as "puts a value at the end of a function's parameter list" and you'll have the right idea.
In F# any if/else/then-statement must evaluate to the same type of value for all branches. Since you've omitted the else-branch of the expression, the compiler will infer it to return a value of type unit, effectively turning your if-expression into this:
if ip.AddressFamily = AddressFamily.InterNetwork then
ip.ToString() // value of type string
else
() // value of type unit
Scott Wlaschin explains this better than me on the excellent F# for fun and profit.
This should fix the current error, but still won't compile. You can solve this either by translating the C#-code more directly (using a mutable variable for the localIP value, and doing localIP <- ip.ToString() in your if-clause, or you could look into a more idiomatic approach using something like Seq.tryFind.
I just began toying around with F# in Mono and the following problem arose that I cannot quite understand. Looking up information on printfn and TextWriterFormat didn't bring enlightenment either, so I thought I'm going to ask here.
In FSI I run the following:
> "hello";;
val it : string = "hello"
> printfn "hello";;
hello
val it : unit = ()
Just a normal string and printing it. Fine. Now I wanted to declare a variable to contain that same string and print it as well:
> let v = "hello" in printfn v ;;
let v = "hello" in printfn v ;;
---------------------------^
\...\stdin(22,28): error FS0001: The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>'
I understood from my reading that printfn requires a constant string. I also understand that I can get around this problem with something like printfn "%s" v.
However, I'd like to understand what's going on with the typing here. Clearly, "hello" is of type string as well as v is. Why is there a type problem then? Is printfn something special? As I understand it the compiler already performs type-checking on the arguments of the first string, such that printfn "%s" 1 fails.. this could of course not work with dynamic strings, but I assumed that to be a mere convenience from the compiler-side for the static case.
Good question. If you look at the type of printfn, which is Printf.TextWriterFormat<'a> -> 'a, you'll see that the compiler automatically coerces strings into TextWriterFormat objects at compile time, inferring the appropriate type parameter 'a. If you want to use printfn with a dynamic string, you can just perform that conversion yourself:
let s = Printf.TextWriterFormat<unit>("hello")
printfn s
let s' = Printf.TextWriterFormat<int -> unit>("Here's an integer: %i")
printfn s' 10
let s'' = Printf.TextWriterFormat<float -> bool -> unit>("Float: %f; Bool: %b")
printfn s'' 1.0 true
If the string is statically known (as in the above examples), then you can still have the compiler infer the right generic argument to TextWriterFormat rather than calling the constructor:
let (s:Printf.TextWriterFormat<_>) = "hello"
let (s':Printf.TextWriterFormat<_>) = "Here's an integer: %i"
let (s'':Printf.TextWriterFormat<_>) = "Float: %f; Bool: %b"
If the string is truly dynamic (e.g. it's read from a file), then you'll need to explicitly use the type parameters and call the constructor as I did in the previous examples.
This is only somewhat related to your question, but I think it's a handy trick. In C#, I often have template strings for use with String.Format stored as constants, as it makes for cleaner code:
String.Format(SomeConstant, arg1, arg2, arg3)
Instead of...
String.Format("Some {0} really long {1} and distracting template that uglifies my code {2}...", arg1, arg2, arg3)
But since the printf family of methods insist on literal strings instead of values, I initially thought that I couldn't use this approach in F# if I wanted to use printf. But then I realized that F# has something better - partial function application.
let formatFunction = sprintf "Some %s really long %i template %i"
That just created a function that takes a string and two integers as input, and returns a string. That is to say, string -> int -> int -> string. It's even better than a constant String.Format template, because it's a strongly-typed method that lets me re-use the template without including it inline.
let foo = formatFunction "test" 3 5
The more I use F#, the more uses I discover for partial function application. Great stuff.
I don't think that it is correct to say that the literal value "hello" is of type String when used in the context of printfn "hello". In this context the compiler infers the type of the literal value as Printf.TextWriterFormat<unit>.
At first it seemed strange to me that a literal string value would have a different inferred type depending on the context of where it was used, but of course we are used to this when dealing with numeric literals, which may represent integers, decimals, floats, etc., depending on where they appear.
If you want to declare the variable in advance of using it via printfn, you can declare it with an explicit type...
let v = "hello" : Printf.TextWriterFormat<unit> in printfn v
...or you can use the constructor for Printf.TextWriterFormat to convert a normal String value to the necessary type...
let s = "foo" ;;
let v = new Printf.TextWriterFormat<unit>(s) in printfn v ;;
As you correctly observe, the printfn function takes a "Printf.TextWriterFormat<'a>" not a string. The compiler knows how to convert between a constant string and a "Printf.TextWriterFormat<'a>", but not between a dynamic string and a "Printf.TextWriterFormat<'a>".
This begs the question why can't it convert between a dynamic string and a "Printf.TextWriterFormat<'a>". This is because the compiler must look at the contents of the string to and determine what control characters are in it ( i.e. %s %i etc), from this is it works out the type of the type parameter of "Printf.TextWriterFormat<'a>" (i.e. the 'a bit). This is a function that is returned by the printfn function and means that the other parameters accepted by printfn are now strongly typed.
To make this a little clear in your example "printfn "%s"" the "%s" is converted into a "Printf.TextWriterFormat unit>", meaning the type of "printfn "%s"" is string -> unit.