I wrote this function which computes the palindrome of a number :
let palindrome n =
let mutable current = n
let mutable result = 0
while(current > 0) do
result <- result * 10 + current % 10
current <- current / 10
result
How can I rewrite it in a more functional way ?
It's not quite clear what you want to do. The palindrome function as given simply reverses the digits of an integer:
> palindrome 1;;
val it : int = 1
> palindrome 12;;
val it : int = 21
> palindrome 123;;
val it : int = 321
> palindrome 9852;;
val it : int = 2589
Those aren't palindromic numbers, but let's split the problem into smaller building blocks.
You can easily split an integer into a list of digits. In fact, splitting into a reverse list of digits is the easiest way I could think of:
let rec revdigits i =
let tens = i / 10
if tens = 0
then [i]
else
let ones = i % 10
ones :: revdigits tens
This is a function of the type int -> int list.
Examples:
> revdigits 1;;
val it : int list = [1]
> revdigits 12;;
val it : int list = [2; 1]
> revdigits 123;;
val it : int list = [3; 2; 1]
> revdigits 9852;;
val it : int list = [2; 5; 8; 9]
It's also easy to concatenate a list of digits into a number:
let rec concat digits =
match digits with
| [] -> 0
| h :: t -> h * int (10. ** float t.Length) + concat t
This function has the type int list -> int.
Examples:
> concat [1];;
val it : int = 1
> concat [1; 2];;
val it : int = 12
> concat [1; 2; 3];;
val it : int = 123
> concat [2; 5; 8; 9];;
val it : int = 2589
With these building blocks, you can easily compose a function that does the same as the palindrome function:
let reverse = revdigits >> concat
This function has the type int -> int.
Examples:
> reverse 1;;
val it : int = 1
> reverse 12;;
val it : int = 21
> reverse 123;;
val it : int = 321
> reverse 2589;;
val it : int = 9852
Bonus: if you don't want to reverse the digits, you can do it like this instead, but I don't think this version is tail recursive:
let rec digits i =
let tens = i / 10
if tens = 0
then [i]
else
let ones = i % 10
digits tens # [ones]
This function has the type int -> int list.
Examples:
> digits 1;;
val it : int list = [1]
> digits 12;;
val it : int list = [1; 2]
> digits 123;;
val it : int list = [1; 2; 3]
> digits 9852;;
val it : int list = [9; 8; 5; 2]
You can do it with a tail-recursive function. Match the value of result : if his value = 0 then return the result else do the computations on current and result.
let palindrome n =
let rec rec_palindrome current result = match current with
| 0 -> result
| _ -> rec_palindrome (result * 10 + current % 10) (current / 10)
rec_palindrome n 0
Plus, in my version, this is no mutable values.
Related
Can anyone help me with this problem?
"Realize a function which duplicate each item in a list. You can use List.map"
IN F# sharp language.
And also
"Use the List.init function to generate a list of n random natural numbers between 0 and m."
let makeCopy elem Count =
match Count with
| 0 -> []
| 1 -> elem
let rec dupeElem row count =
match row with
| [] -> []
| hd::tl -> (makeCopy hd count) # dupeElem tl count
//let xs = [1; 2; 3]
//xs |> List.collect (fun x -> List.replicate 3 x)
//val it : int list = [1; 1; 2; 2; 3; 3]
Duplicating the items is pretty straight forward, you just need a recursive function that walks the list.
Generating the random numbers is where you can use List.init to create a new list. You can use the .NET Random class to generate the random numbers you're after.
This gives up the following functions:
let rec duplicateItems list =
match list with
| [] -> []
| head :: tail -> head :: head :: duplicateItems tail
let makeRandomList count upperBound =
let random = Random()
List.init count (fun i -> random.Next(0, upperBound))
You can now generate a random list and pipe it into the duplicate function:
let numbers = makeRandomList 10 20 |> duplicateItems
NOTE: duplicateItems is not tail recursive, so for really large lists this might be an issue. You can get around this by treating the data to duplicate as a sequence:
let duplicateSequence sequence =
seq {
for a in sequence do
yield a
yield a
}
Now we just need to pipe the result into Seq.toList:
let numbers = makeRandomList 10 20 |> duplicateSequence |> Seq.toList
We could also have written makeRandom to return a sequence rather than a list. This would have made the whole computation lazy up until the point we call Seq.toList.
which duplicate each item in a list. You can use List.map
I think your own solution with List.collect is fine. But here's one with List.map:
> let dupe x = List.map (fun s -> [s;s]) x |> List.concat
val dupe : x:'a list -> 'a list
> dupe [1;2;3];;
val it : int list = [1; 1; 2; 2; 3; 3]
Use the List.init function to generate a list of n random natural numbers between 0 and m
I'll show you the general idea, then you can work out the rest, I'm sure. This basically works:
> let rand n max = let r = Random() in List.init n (fun _ -> r.Next(0, max));;
val rand : n:int -> max:int -> int list
> rand 10 12;;
val it : int list = [11; 11; 10; 11; 6; 1; 3; 6; 8; 2]
I want to create a label in F# which uses a mutable variable to return a value. Unfortunately F# sets this label to a constant value. If the value of the mutable changes, the value of the label remains. Isn't it a bit inconsistent? Is there a way to get the label ("a") being dependent of the mutable ("x")?
let mutable x = 0;
let a = x + 2; // I want not to set a to a constant value
let b two = x + two;
x <- 1;
let c = b 2;
let isConsistent = a = c;
val mutable x : int = 1
val a : int = 2
val b : two:int -> int
val c : int = 3
val isConsistent : bool = false
From your own comment you want a to be a function returning x + 2
Direct translation of that is :
let mutable x = 0
let a () = x + 2
let b two = x + two
x <- 1
let c = b 2
let isConsistent = a () = c // don't forget to call the function 'a'
(*
val mutable x : int = 1
val a : unit -> int
val b : two:int -> int
val c : int = 3
val isConsistent : bool = true
*)
I am trying to truncate this sequence like you can do with arrays in F#
let sublist sequ (i:int) (n:int) =
let item = Seq.item(n-i) sequ
let start = Seq.item i sequ
let ending = Seq.item n sequ
Seq.truncate(item) (seq{start..ending})
sublist [|25..92|] 5 10
like it can be done here
Array.sub [|5..20|] 3 10
You forgot to write the expected results.
You can use take and skip as in the linked answer in the comments:
let sublist sequ (i:int) (n:int) =
sequ |> Seq.skip i |> Seq.take (n-1)
Notice that if you are dealing with arrays you can use array slices:
[|25..92|].[5..10]
>
val it : int [] = [|30; 31; 32; 33; 34; 35|]
[|5..20|].[3..10]
>
val it : int [] = [|8; 9; 10; 11; 12; 13; 14; 15|]
Take this function as an example:
// Sequence of random numbers
open System
let randomSequence m n =
seq {
let rng = Random ()
while true do
yield rng.Next (m, n)
}
randomSequence 8 39
The randomSequence function takes two arguments: m, n. This works fine as a normal function. I would like to set the default for m, n, for example:
(m = 1, n = 100)
When there's no arguments given, the function take the default value. Is it possible in F#?
You can often achieve the same effect as overloading with a Discriminated Union.
Here's a suggestion based on the OP:
type Range = Default | Between of int * int
let randomSequence range =
let m, n =
match range with
| Default -> 1, 100
| Between (min, max) -> min, max
seq {
let rng = new Random()
while true do
yield rng.Next(m, n) }
Notice the introduction of the Range Discriminated Union.
Here are some (FSI) examples of usage:
> randomSequence (Between(8, 39)) |> Seq.take 10 |> Seq.toList;;
val it : int list = [11; 20; 36; 30; 35; 16; 38; 17; 9; 29]
> randomSequence Default |> Seq.take 10 |> Seq.toList;;
val it : int list = [98; 31; 29; 73; 3; 75; 17; 99; 36; 25]
Another option is to change the randomSequence ever so slightly to take a tuple instead of two values:
let randomSequence (m, n) =
seq {
let rng = new Random()
while true do
yield rng.Next(m, n) }
This would allow you to also define a default value, like this:
let DefaultRange = 1, 100
Here are some (FSI) examples of usage:
> randomSequence (8, 39) |> Seq.take 10 |> Seq.toList;;
val it : int list = [30; 37; 12; 32; 12; 33; 9; 23; 31; 32]
> randomSequence DefaultRange |> Seq.take 10 |> Seq.toList;;
val it : int list = [72; 2; 55; 88; 21; 96; 57; 46; 56; 7]
Optional parameters are permitted only on members [...]
https://msdn.microsoft.com/en-us/library/dd233213.aspx
So, for your current example, I think it is impossible.
But you could wrap the functionality:
type Random =
static member sequence(?m, ?n) =
let n = defaultArg n 100
let rng = new System.Random()
match m with
| None -> Seq.initInfinite (fun _ -> rng.Next(1, n))
| Some(m) -> Seq.initInfinite (fun _ -> rng.Next(m, n))
and then use it like this:
let randomSequence = Random.sequence(2, 3)
let randomSequence' = Random.sequence(n = 200)
let randomSequence'' = Random.sequence()
Explanation: optional parameters can either be fully Optional (m) or defaultArgs (n). I like shadowing (reusing the same name) these parameters, but that's debatable.
This seems to be the most elegant solution to this problem:
//define this helper function
let (|Default|) defaultValue input =
defaultArg input defaultValue
//then specify default parameters like this
let compile (Default true optimize) =
optimize
//or as the OP asks
let randomSequence (Default 1 m) (Default 100 n) =
seq {
let rng = new System.Random()
while true do
yield rng.Next(m,n)
}
Credits:
http://fssnip.net/5z
let randomSequence m n=
seq {
let rng = new Random()
while true do
yield rng.Next(m,n)
}
let randomSequenceWithDefaults() =
randomSequence 1 100
So instead, call randomSequenceWithDefaults()
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