I'm trying to print a factorial talbe:
Input: an int n.
Output: a table of factorial results from 1! to n!.
Here is what I did:
let toBigInt (n: int) = bigint(n) // Convert an "int" to a "bigint".
// Factorial with bigint support:
let fac n =
[1..n]
|> List.map toBigInt
|> List.reduce (*)
let printFacTable n =
let listNum = [1 .. n]
let listFac = listNum |> List.map fac
let numFacPair = List.zip listNum listFac
for (k, v) in numFacPair
do printfn "%d ! = %A" k v
The result:
> printFacTable 12;;
1 ! = 1
2 ! = 2
3 ! = 6
4 ! = 24
5 ! = 120
6 ! = 720
7 ! = 5040
8 ! = 40320
9 ! = 362880
10 ! = 3628800
11 ! = 39916800
12 ! = 479001600
val it : unit = ()
The result is fine. I would like to vertical align the ! = by adjust paddings in front of the !. Let's say this program accept up to 8 digits number as input. I guess the padding should be:
let padding = 8 - eachNum.length
But I don't know how to put it into the program block. Any idea?
As detailed in the Printf module documentation, you simply need to specify the width of the field:
printfn "%8d ! = %A" k v
Try this:
do printfn "%8d ! = %A" k v
I think it's better to format on the left side:
for (k, v) in numFacPair
do printfn "%-2d ! = %A" k v
Then printFacTable 12:
1 ! = 1
2 ! = 2
3 ! = 6
4 ! = 24
5 ! = 120
6 ! = 720
7 ! = 5040
8 ! = 40320
9 ! = 362880
10 ! = 3628800
11 ! = 39916800
12 ! = 479001600
Link: http://ideone.com/gJeK0B
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Ok so i am working on a small project as you can tell in the title i am making an BrainFuck interpeter in f# and i am new to this language but it is fun except that you fight with the compiler lot but i am used to it cause i used to use rust but aside the point it looks like to me it is only executing the symbols once. I know this is not efficient or fully functional but right now i am just going that works. Here is my code
main.fs
open System
open System.IO
let mutable reg : int array = Array.zeroCreate 50
let mutable ptr = 0
let mutable larr : int array = Array.zeroCreate 50
let mutable lptr = 0
let mutable pc = 0
let result = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
let prog = result.ToCharArray()
let startLoop =
larr.[lptr] <- pc
printfn "STARTING LOOP AT %d" larr.[lptr]
lptr <- lptr + 1
let doEnd =
pc <- larr.[lptr]
while larr.[lptr - 1] > 0 do
ptr <- larr.[lptr - 1]
larr.[lptr - 1] <- larr.[lptr - 1] - 1
let endLoop =
lptr <- lptr - 1
if reg.[ptr] = 0 then pc <- pc
else doEnd
let doPlus =
reg.[ptr] <- (reg.[ptr] + 1) % 265
printfn "ADDING"
let doMinus =
reg.[ptr] <- (reg.[ptr] - 1) % 265
printfn "SUB"
let doInc =
ptr <- (ptr + 1) % 265
printfn "INC"
let doDec =
ptr <- (ptr - 1) % 265
printfn "MINUS"
let doPrt =
printfn "%c" (reg.[ptr] |> char)
let doSloop =
startLoop
printfn "START LOOP"
let doEloop =
endLoop
printfn "END LOOP"
let exec =
while pc < prog.Length do
let i = prog.[pc]
if i = '+' then doPlus
elif i = '-' then doMinus
elif i = '>' then doInc
elif i = '<' then doDec
elif i = '.' then doPrt
elif i = '[' then doSloop
elif i = ']' then doEloop
else 1 |> ignore
pc <- pc + 1
exec
Welcome to the F# community.
Here is a more functional style of writing your program. It's just a start, but I hope it will give you some ideas about how to proceed. Ultimately, you'll want to avoid mutable values if at all possible, and probably the first step to doing that would be to write functions that have parameters other than unit.
let result = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
let doPlus () =
// reg.[ptr] <- (reg.[ptr] + 1) % 265
printfn "ADDING"
let doMinus () =
// reg.[ptr] <- (reg.[ptr] - 1) % 265
printfn "SUB"
let doDefault () = printfn ""
let funcs =
[|
'+', doPlus
'-', doMinus
|] |> Map.ofArray
let exec () =
result
|> Seq.iteri (fun i c ->
printf "%03d: " i
match funcs.TryFind(c) with
| Some func -> func ()
| None -> doDefault ()
)
exec ()
I want to convert a given integer into a base 4 string. For eg : In scala,
var str: String = Integer.toString(10, 4)
gives the output "22" ie 2*(4^1) + 2*(4^0) = 10
Im having difficulty doing this in F#. Any help is appreciated
let intToDigits baseN value : int list =
let rec loop num digits =
let q = num / baseN
let r = num % baseN
if q = 0 then
r :: digits
else
loop q (r :: digits)
loop value []
254
|> intToDigits 16
|> List.fold (fun acc x -> acc + x.ToString("X")) ""
|> printfn "%s"
254
|> intToDigits 4
|> List.fold (fun acc x -> acc + x.ToString()) ""
|> printfn "%s"
This outputs FE for the base-16 conversion and 3332 for the base-4 conversion. Note that ToString("X") works for up to base 16, so it could be used for the base-4 conversion too.
I adapted this int based solution from Stuart Lang's bigint example (which uses bigint.DivRem rather than integer operators).
I'm pretty new to programming in F#, and I am working on a project at the moment, with a function that takes an integer and returns a string value.
My problem (se my code below) is that no matter what I do, I cant return the values of my str, calling my function.
let mulTable (n:int):string = string n
let mutable m = 1
let mutable str = ""
while m < 10 do
str <- "m\t" + str
m <- m + 1
printfn "%A" (mulTable str)
My idea here is that I want to store the value of m, in str, så that str in the end of my while loop contains the values of "1 2 3 4 5 6 7 8 9". But no matter what I try my printfn "%A" mulTable str, returns "this expressions was exspected to have type int, but here has type string". I have tried converting my str to a string in my mutable value like:
let mutable str = ""
let mutable str1 = str |> int
and then I try to call my str1 using function mulTable instead of calling str. But still it does not work.
What am I missing here? I've been trying every single possible solution I can think of, without being able to solve my problem.
A fix of your own algorithm could be:
let getSequenceAsString max =
let concat s x = sprintf "%s\t%i" s x
let mutable m = 1
let mutable str = ""
while m < max do
str <- concat str m
m <- m + 1
str
printfn "%A" (getSequenceAsString 10)
But as others have shown it's a lot of work that can be done more easily:
open System
let getSequenceAsString max =
String.Join("\t", [1..max-1])
If you want each number reverted as you ask for in a comment it could be done this way:
let getSequenceAsString min max =
let revert x =
let rec rev y acc =
match y with
| 0 -> acc
| _ -> rev (y / 10) (sprintf "%s%i" acc (y % 10))
rev x ""
String.Join("\t", ([min..max-1] |> List.map revert))
printfn "%A" (getSequenceAsString 95 105)
Gives:
"59 69 79 89 99 001 101 201 301 401"
You can easily join an array of strings into a string array, and then print it out if necessary.
open System
let xs = [1..9] |> List.map string
//you should avoid using mutable variables, and instead generate your list of numbers with an list comprehension or something similar.
String.Join("\t", xs)
//A little exploration of the List/Array/String classes will bring this method up: "concatenates the members of a collection using the separator string.
This gives me:
val it : string = "1 2 3 4 5 6 7 8 9"
I've adjusted the code to make it produce results similar to what you wanted:
let mulTable (n:int):string = string n
let mutable m = 1
let mutable str = ""
while m < 10 do
str <- mulTable m+ "\t" + str
m <- m + 1
printfn "%A" (str)
I've used your mulTable to convert m to string, but for printfn you don't need to use that, because str is already a string.
Still the result would be 9 8 7 6 5 4 3 2 1
There are more then one way to revert the string, one of them would be to split the string into an array of characthers and then revert the array. From resulting array we will build a new string again. It would look something like:
printf "%A" (new System.String(str.ToCharArray() |> Array.rev ))
Edit
To achieve the same result, I would suggest to use more functional style, using recursion and avoiding mutating variables.
let getNumbersString upperLimit =
let rec innerRecursion rem acc=
match rem with
| 0 -> acc
| _ -> innerRecursion (rem-1) (sprintf "%i "rem::acc)
innerRecursion upperLimit [] |> String.concat ""
getNumbersString 9
Will result in
val it : string = "1 2 3 4 5 6 7 8 9 "
string s = "foo.bar"
s[s.LastIndexOf(".")] = "-"
It sounds dead simple in c-like languages, but drives me nuts in F#
my code:
let sb = new StringBuilder(s)
sb.[s.LastIndexOf(".")] <- '-'
let s = sb.ToString()
Is there more elegant way to do this? Like using |> ? I don't want to explicitly declare a new variable sb.
Alternatively, you can do this as follows:
let s = "foo.bar"
let index = s.LastIndexOf('.')
let s1 = s |> String.mapi(fun i x -> if i=index then '-' else x)
s1 |> printfn "%A"
Print: "foo-bar"
Link: https://dotnetfiddle.net/5FjFR1
There are already good suggestions here. Here's another way to do it:
let s = "foo.bar"
let idx = s.LastIndexOf '.'
let replaced = s.Substring(0, idx) + "-" + s.Substring(idx + 1)
You could work with char array directly instead of wrapped with StringBuilder.
let replaceAt i c (s: string) =
let arr = s.ToCharArray()
arr.[i] <- c
String arr
"foo.bar" |> replaceAt 3 '-'
Some tests comparing it with this one using mapi—
let replaceAt2 index x s = s |> String.mapi (fun i x -> if i=index then '-' else x)
let test f =
let rec loop n =
if n > 0 then
let x = "foo.bar" |> f 3 '-'
loop (n - 1)
loop 10000000
test replaceAt // Real: 00:00:01.188, CPU: 00:00:01.201, GC gen0: 168, gen1: 168, gen2: 0
test replaceAt2 // Real: 00:00:05.587, CPU: 00:00:05.584, GC gen0: 275, gen1: 275, gen2: 0
Just for the fun of it I tried a "more" functional approach with List.foldBack. Try the code below for yourself at .NET Fiddle.
let replaceLastOf candidate replacement l =
let replaceAndPrepend x (xs, found) =
if not found && x = candidate
then (replacement::xs, true)
else (x::xs, found)
fst <| List.foldBack replaceAndPrepend l ([], false)
let replaceLastCharOf candidate replacement (str:string) =
List.ofSeq str
|> replaceLastOf candidate replacement
|> Array.ofList
|> System.String.Concat
Usage:
printfn "%A" (replaceLastOf 1 9 [1;3;1;4;1])
printfn "%A" (replaceLastCharOf '.' '-' "f.oo.bar")
Output:
[1; 3; 1; 4; 9]
"f.oo-bar"
Ok, this looks like it should be easy, but I'm just not getting it. If I have a sequence of numbers, how do I generate a new sequence made up of the running totals? eg for a sequence [1;2;3;4], I want to map it to [1;3;6;10]. In a suitably functional way.
Use List.scan:
let runningTotal = List.scan (+) 0 >> List.tail
[1; 2; 3; 4]
|> runningTotal
|> printfn "%A"
Seq.scan-based implementation:
let runningTotal seq' = (Seq.head seq', Seq.skip 1 seq') ||> Seq.scan (+)
{ 1..4 }
|> runningTotal
|> printfn "%A"
Another variation using Seq.scan (Seq.skip 1 gets rid of the leading zero):
> {1..4} |> Seq.scan (+) 0 |> Seq.skip 1;;
val it : seq<int> = seq [1; 3; 6; 10]
> Seq.scan (fun acc n -> acc + n) 0 [1;2;3;4];;
val it : seq<int> = seq [0; 1; 3; 6; ...]
With lists:
> [1;2;3;4] |> List.scan (fun acc n -> acc + n) 0 |> List.tail;;
val it : int list = [1; 3; 6; 10]
Edit: Another way with sequences:
let sum s = seq {
let x = ref 0
for i in s do
x := !x + i
yield !x
}
Yes, there's a mutable variable, but I find it more readable (if you want to get rid of the leading 0).
Figured it was worthwhile to share how to do this with Record Types in case that's also what you came here looking for.
Below is a fictitious example demonstrating the concept using runner laps around a track.
type Split = double
type Lap = { Num : int; Split : Split }
type RunnerLap = { Lap : Lap; TotalTime : double }
let lap1 = { Num = 1; Split = 1.23 }
let lap2 = { Num = 2; Split = 1.13 }
let lap3 = { Num = 3; Split = 1.03 }
let laps = [lap1;lap2;lap3]
let runnerLapsAccumulator =
Seq.scan
(fun rl l -> { rl with Lap = l; TotalTime = rl.TotalTime + l.Split }) // acumulator
{ Lap = { Num = 0; Split = 0.0 }; TotalTime = 0.0 } // initial state
let runnerLaps = laps |> runnerLapsAccumulator
printfn "%A" runnerLaps
Not sure this is the best way but it should do the trick
let input = [1; 2; 3; 4]
let runningTotal =
(input, 0)
|> Seq.unfold (fun (list, total) ->
match list with
| [] ->
None
| h::t ->
let total = total + h
total, (t, total) |> Some)
|> List.ofSeq