How to print a bigint in F#? - f#

I am trying to find out how to print out the value of a bigint or System.Numerics.BigInteger in F#. I have found a site here that attempts to explain how to do this, but in the Visual Studio editor, it is flagged as an error. So far, I am just trying something simple like:
printfn "bigInt: %A " 123456789I
But that gets flagged as:
Why does this not work? How can I print out a bigint?
Code:
[<EntryPoint>]
let main =
printfn "bigInt: %A " 123456789I

If you are using an explicit entry point, main needs to accept a single string[] argument and return int. Your sample code is missing both of those requirements. Your printfn line is fine.
[<EntryPoint>]
let main (argv : string[]) =
printfn "bigint %A" 12345I
0

Related

F#: How exactly is ToString supposed to be used?

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)

How can I wrap sprintf + a call into a single function, and have two signatures, in F#?

I have a function that takes a string and sends it to a terminal:
Print: string -> unit
it is passed to several modules that do this, to simplify the syntax
// printing
let print = settings.Print
and then it's used like that:
print "hello"
print (sprintf "the time is %A" DateTime.UtcNow)
my question is: Can I make two functions, with the same name but two signatures, so I could use it to either print a string, or a sprintf, then print the string.
for example:
print "hello"
print "the time is %A" DateTime.UtcNow
Is this possible? the goal is to simplify the syntax as a lot of code is peppered with info being sent to the terminal (which is currently a Telegram channel)
You can use kprintf for this:
let myPrint s = printfn "My print: %s !" s
let print x = Printf.kprintf myPrint x
print "%d" 1
print "aaaa"
print "%s %s" "b" "c"
There are some examples here and here.
I couldn't find kprintf documentation, so I'm not sure that this usage is correct, but it produces the correct result for me. Another possible candidate is ksprintf, which also produces the same result.
You can use the same signature as sprintf:
let print (format : Printf.StringFormat<'T>) =
sprintf format
|> dosomethingElse
and you can use it as you want:
print "hello"
print "the time is %A" DateTime.UtcNow

Matching command line args

Starting out learning F#. Want to make a simple program that just tells me what it found in the command line args. I have:
[<EntryPoint>]
let main argv =
printfn "%A" argv
match argv with
| [] -> 42
| _ -> 43
But this gives errors. If I hover over argv I see:
val argv : string[]
which is what I would have expected (a list of strings). However the first match expression has an error:
Error 1 This expression was expected to have type
string [] but here has type
'a list
Basically I just want to match on an empty argument list (an empty list of strings). What's the right way to do that?
I should add: I don't just want a solution (though that would be nice). I also want to understand what the compiler is looking for here that I'm not giving it.
It might be confusing since [] literal is used to signify an empty list, but type string [] is an array of strings rather than a list.
You can pattern match against an array like this:
[<EntryPoint>]
let main argv =
printfn "%A" argv
match argv with
| [||] -> 42
| _ -> 43
Like many seemingly inconsistent things in F#, this is a result of its dual heritage.
In OCaml, you'd use int list and int array for the types, [1;2;3] and [|1;2;3|] for the values respectively. But in C#/.NET, square brackets as in int[] are the way to indicate you're dealing with an array.
Probably in an attempt to be more approachable for the .NET crowd, in type names F# uses [] as an alias for array, so both forms are usable. It's rather unfortunate that this coincides with the empty list literal, but leaving that 'as is' was another constraint - one of early goals in F# design was to make it compatible with OCaml code, so that porting from that language to F# is as friction-less as possible.
If you want to implement some command-line utility I suggest using a wonderful library https://github.com/JordanMarr/FSharp.SystemCommandLine or https://github.com/cannorin/FSharp.CommandLine is also good.
But if you want to do that by hand, try
[<EntryPoint>]
let main (argv : string list) =
printfn "%A" argv
match argv with
| [] -> 42
| _ -> 43
or
[<EntryPoint>]
let main argv =
printfn "%A" argv
match argv |> List.ofArray with
| [] -> 42
| _ -> 43

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.

No input from F# printf

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

Resources