wrapping printf and still take parameters - f#

/// Colored printf
let cprintf c fmt =
Printf.kprintf
(fun s ->
let old = System.Console.ForegroundColor
try
System.Console.ForegroundColor <- c;
System.Console.Write s
finally
System.Console.ForegroundColor <- old)
fmt
// Colored printfn
let cprintfn c fmt =
cprintf c fmt
printfn ""
With the above stolen code,
cprintfn ConsoleColor.Yellow "This works"
but
cprintfn ConsoleColor.Yellow "This %s" "doesn't"
(cprintfn ConsoleColor.Yellow) "still %s" "doesn't"
(cprintfn ConsoleColor.Yellow "still %s") "doesn't"
cprintfn ConsoleColor.Yellow ("still %s" "doesn't")
I know this has to do with Printf.TextWriterFormat<_> vs simple strings but even specifying a type for fmt as in cprintf c (fmt:Printf.TextWriterFormat<_>), I can't get the kprintf part to work. I read a bunch of answers related to logging, but I still can't figure it out. Is a cprintf that takes format parameters possible?

First of all, your cprintf function is perfectly fine and you can use it with variable number of arguments. The problem is only with the cprintfn function:
cprintf System.ConsoleColor.Red "%s %d" "hi" 42
The problem is that when you're defining a function that uses formatting string, you always need to use partial application. That is your function has to be of the form:
let myprintf fmt =
<whatever>
otherprintf <whatever> fmt
The important thing is that otherprintf <whatever> fmt has to be the last part of the body and it has to take fmt as the last argument. This way, when otherprintf needs more arguments (as specified by fmt) these are automatically propagated and become arguments of myprintf.
This means that defining cprintfn in terms of cprintf is actually quite tricky. But you can always define a helper function that is a bit more powerful and lets you do both:
let cprintfWith endl c fmt =
Printf.kprintf
(fun s ->
let old = System.Console.ForegroundColor
try
System.Console.ForegroundColor <- c;
System.Console.Write (s + endl)
finally
System.Console.ForegroundColor <- old)
fmt
let cprintf c fmt = cprintfWith "" c fmt
let cprintfn c fmt = cprintfWith "\n" c fmt

Related

F# - Ask for 3 numbers and then find the minimum?

I am new to programming so this should be an easy one.
I want to write a code that asks for 3 numbers and then finds the minimum. Something like that:
let main(): Unit =
putline ("Please enter 3 numbers:")
putline ("First number: ")
let a = getline ()
putline ("Second number: ")
let b = getline ()
putline("Third number: ")
let c = getline ()
if (a<b && a<c) then putline ("Minimum:" + a)
elif (b<c && b<a) then putline ("Minimum:" + b)
else putline ("Minimum:" + c)
I am sorry if this is terrible but I am still new to this. Also I am not allowed to use the dictionary. Any advice?
You can use the F# function min, which gives you the minimum of two values.
min 1 2 // 1
To get the minimum of three values you can use it twice:
min (min a b) c
A cleaner way to write this with F# piping is:
a |> min b |> min c
Alternatively, put the items in a list and use List.min:
[ a; b; c ] |> List.min
If, for some reason, you decide to expand beyond three numbers, you could consider using Seq.reduce
let xs = [0;-5;3;4]
xs
|> Seq.reduce min
|> printfn "%d"
// prints -5 to stdout
You can use min as the reducer because it accepts 2 arguments, which is exactly what Seq.reduce expects
Firstly your putline function. I'm assuming that this is supposed to take a value and print it to the console with a newline, so the built in F# command to do this is printfn and you would use it something like this:
let a = 1
printfn "Minimum: %d" a
The %d gets replaced with the value of a as, in this case, a is an integer. You would use %f for a float, %s for a string... the details will all be in the documentation.
So we could write your putline function like this:
let putline s = printfn "%s" s
This function has the following signature, val putline : s:string -> unit, it accepts a string and return nothing. This brings us onto your next problem, you try and say putline ("Minimum:" + a). This won't work as adding a number and a string isn't allowed, so what you could do is convert a to a string and you have several ways to do this:
putline (sprintf "Minimum: %d" a)
putline ("Minimum:" + a.ToString())
sprintf is related to printfn but gives you back a string rather than printing to the console, a.ToString() converts a to a string allowing it to be concatenated with the preceding string. However just using printfn instead of putline will work here!
You also have a logic problem, you don't consider the cases where a == b == c, what's the minimum of 1,1,3? Your code would say 3. Try using <= rather than <
For reading data from the console, there is already an answer on the site for this Read from Console in F# that you can look at.

The block following this 'let' is unfinished, F# error

I've been trying to create a code in F# that can read text via another file, however I keep seeing a
The block following this 'let' is unfinished. Every code block is an expression and must have a result
on the
let a = line.Split delim
,I looked it up and thought it was an indentation error but that didn't fix that. Any advice?
[<EntryPoint>]
let main argv =
let delim = ','
use stream = new StreamReader #"final.txt"
let line = stream.Readline()
let a = line.Split delim
|>Seq.map System.Int32.Parse
|>Seq.toArray
printfn "Orignal numbers: %A" a
printfn "Ordered numbers: %A" (oddEven a)
0 // return an integer exit code
You're missing indentation (and misspelled a thing or two). Anything that you want to be part of a let block has to be indented one level. Here's your code properly formatted:
[<EntryPoint>]
let main argv =
let delim = ','
use stream = new StreamReader #"final.txt"
let line = stream.ReadLine()
let a =
line.Split delim
|> Seq.map System.Int32.Parse
|> Seq.toArray
printfn "Orignal numbers: %A" a
printfn "Ordered numbers: %A" (oddEven a)
0 // return an integer exit code

Initialize function with standard input

I am facing a problem that leave me disoriented, since it should be a pretty basic procedure. I am learning how to build simple console applications with F#, but I cannot figure out how to pass an integer as standard input to the program. Please consider:
open System
let square x = x * x
[<EntryPoint>]
let main (argv :string[]) =
printfn "The function will take an input and square it"
printfn "%d squared is %d" 12 (square 12)
Console.ReadLine() |> ignore
0
How can I pass the value to printfn and square the way I can do in C with:
int main(){
int i;
scanf("%d", &i);
printf("\nThe value of variable i is %d.\n", i);
return 0;
}
I tried to adapt let x = Console.ReadLine() to get integers, but no appreciable results. The documentation I consulted, mainly consider string inputs. I am afraid I am missing something important for properly comprehend the basic of F#. Any suggestion, in this sense, would be highly appreciated.
ReadLine () will return a string. As mentioned by #JohnPalmer, it needs to be parsed to an int. The following program should give you the basic idea:
let rec input () =
printf "Input: "
match Core.int.TryParse (stdin.ReadLine ()) with
| true, i -> i
| _ ->
printfn "Invalid input, try again"
input ()
let square x = x * x
[<EntryPoint>]
let main _ =
printfn "The function will take an input and square it"
let i = input ()
printfn "%d squared is %d" i (square i)
0

Magic sprintf function - how to wrap it?

I am trying to wrap a call to sprintf function. Here's my attempt:
let p format args = "That was: " + (sprintf format args)
let a = "a"
let b = "b"
let z1 = p "A %s has invalid b" a
This seems to work, output is
val p : format:Printf.StringFormat<('a -> string)> -> args:'a -> string
val a : string = "a"
val b : string = "b"
val z1 : string = "That was: A a has invalid b"
But it wouldn't work with more than one arg:
let z2 = p "A %s has invalid b %A" a b
I get compile-time error:
let z2 = p "A %s has invalid b %A" a b;;
---------^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(7,10): error FS0003: This value is not a function and cannot be applied
How can I create a single function which would work with any number of args?
UPD. Tomas has suggested to use
let p format = Printf.kprintf (fun s -> "This was: " + s) format
It works indeed. Here's an example
let p format = Printf.kprintf (fun s -> "This was: " + s) format
let a = p "something like %d" 123
// val p : format:Printf.StringFormat<'a,string> -> 'a
// val a : string = "This was: something like 123"
But the thing is that main purpose of my function is to do some work except for formatring, so I tried to use the suggested code as follows
let q format =
let z = p format // p is defined as suggested
printf z // Some work with formatted string
let z = q "something like %d" 123
And it doesn't work again:
let z = q "something like %d" 123;;
----------^^^^^^^^^^^^^^^^^^^
stdin(30,15): error FS0001: The type ''c -> string' is not compatible with the type 'Printf.TextWriterFormat<('a -> 'b)>'
How could I fix it?
For this to work, you need to use currying - your function p needs to take the format and return a function returned by one of the printf functions (which can then be a function taking one or more arguments).
This cannot be done using sprintf (because then you would have to propagate the arguments explicitly. However, you can use kprintf which takes a continuation as the first argument::
let p format = Printf.kprintf (fun s -> "This was: " + s) format
The continuation is called with the formatted string and so you can do whatever you need with the resulting string before returning.
EDIT: To answer your extended question, the trick is to put all the additional work into the continuation:
let q format =
let cont z =
// Some work with formatted string
printf "%s" z
Printf.kprintf cont format

Block following this 'let' is unfinished. Expect an expression

Hi everbody I am doing a project with F# but I get this error when ı use let num= line for the following code . I'm new at F# so I can not solve the problem. My code should do this things. User enter a number and calculate the fibonacci but if user enter not a number throw exception
open System
let rec fib n =
match n with
|0->0
|1->1
|2->1
|n->fib(n-1)+fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i));;
let control = true
while control do
try
printfn "Enter a Number:"
let num:int = Convert.ToInt32(stdin.ReadLine())
with
| :? System.FormatException->printfn "Number Format Exception";
let listFibonacci = [for i in 0 .. num-1->fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
control<-false
Console.ReadKey(true)
exit 0;;
I'm not an F# expert but I can see 3 problems with the code you posted.
1) As Lasse V Karlsen commented - f# uses the 'offside' rule so your 'fib' expression needs the body indented in. If you are running this in the Visual Studio Shell it should warn you of this by putting a blue squiggly line under the appropriate code.
2) Both 'control' and 'num' are mutable values so need to be declared explicitly as such.
f# is a functional language so by default any expressions are immutable i.e they are not allowed to change state after they have been declared.
In f#, saying 'let n = expr' does not mean 'assign the value of expr to n' like you would in say c# or c++. Instead it means 'n fundamentally is expr' and will be forever much like a mathematical equation.
So if you want to update the value of a variable you use the special '<-' notation which is the equivalent of 'assign the value on rhs to the lhs' and you need to declare that variable as mutable i.e 'this value can be changed later'
So I think both num and control need to be declared at the top of the loop as
let mutable control = false
let mutable num = 0 // or whatever you want the initial value of num to be
As a side note you don't have to explicitly declare num as an int ( you can if you want ) but f# will infer the type for you
If I understand your code correctly, you want to keep asking for input number n until a valid number is given and print fibonacci numbers up to n. In this case, you'd better move the calculation and printing inside the try block. Here's an updated version with formatting.
open System
let rec fib n =
match n with
|0->0
|1->1
|2->1
|n->fib(n-1)+fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i))
let mutable control = true //you forgot to add the 'mutable' keyword
while control do
try
printfn "Enter a Number:"
let num:int = Convert.ToInt32(stdin.ReadLine())
let listFibonacci = [for i in 0 .. num-1 -> fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
control <- false
with
| :? System.FormatException -> printfn "Number Format Exception"
//add the ignore statement to drop the resulting ConsoleKeyInfo struct
//or the compiler will complain about an unused value floating around.
Console.ReadKey(true) |> ignore
// exit 0 (* Exit isn't necessary *)
Instead of using an imperative style number entry routine and relying on exceptions for control flow, here's a recursive getNumberFromConsole function you could use as well:
open System
let rec fib n =
match n with
| 0 -> 0
| 1 | 2 -> 1
| n -> fib(n-1) + fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i))
//alternative number input, using recursion
let rec getNumberFromConsole() =
match Int32.TryParse(stdin.ReadLine()) with
| (true, value) -> value
| (false, _) -> printfn "Please enter a valid number"
getNumberFromConsole()
printfn "Enter a Number:"
let num = getNumberFromConsole()
let listFibonacci = [for i in 0 .. num-1 -> fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
Console.ReadKey(true) |> ignore
P.S. Thanks for showing me stdin. I never knew it existed. Now I can write some interactive scripts.

Resources