I'm trying to write some code to remove the first N characters in a string. I could have done this in an imperative manner already, but I would like to see it done in the spirit of functional programming. Being new to F# and functional programming, I'm having some trouble...
"Hello world".[n..];;
As #Jeff has shown, you can do this in six characters, so this is not necessarily the best question to ask to see how to "do it in the spirit of functional programming".
I show another way, which is not particularly "functional" (as it uses arrays, but at least it doesn't mutate any), but at least shows a set of steps.
let s = "Hello, world!"
// get array of chars
let a = s.ToCharArray()
// get sub array (start char 7, 5 long)
let a2 = Array.sub a 7 5
// make new string
let s2 = new string(a2)
printfn "-%s-" s2 // -world-
"Hello world".Substring 3
let rec remove_first_n (str:string) (n:int) =
match str, n with
| _, n when n <= 0 -> str
| "", _ -> ""
| _ -> remove_first_n (str.Remove(0,1)) (n-1)
Another way to do it (not particularly functional either). In fact it uses features of both world: mutation and lambda:
let remove_first_n (s:string) (n:int) =
let arr = Array.create (s.Length-n) '0'
String.iteri (fun i c -> if i>=n then arr.[i-n] <- c else ()) s
new string(arr)
That being said, I think the best way is Jeff's solution.
One more thing to keep in mind is that Strings are immutable in .NET (a string value cannot be modified once built) and that F# strings are actually .NET Strings.
Related
I am very new to F# and Kattis. I have tried this simple problem "Which is greater" at Kattis. Link is here: https://open.kattis.com/problems/whichisgreater
I have tried with this code:
open System
let a = Console.Read()
let b = Console.Read()
if a > b then Console.WriteLine "1" else Console.WriteLine "0"
But I still get wrong answer. Anybody who can help on how to handle inputs and outputs in Kattis for F#? Maybe some simple examples can be made available?
The following is accepted by Kattis:
open System
let line = Console.ReadLine().Split ' '
let a = int64 line.[0]
let b = int64 line.[1]
Console.WriteLine(if a > b then 1 else 0)
Here, we read the line, split it on a space character into two numbers, compare them and print the required result.
It looks like they're using an old version of the F# compiler, so you have to specify an explicit entry point. Here's their sample F# solution for a different problem:
open System
[<EntryPoint>]
let main argv =
(fun _ -> Console.ReadLine()) |>
Seq.initInfinite |>
Seq.takeWhile ((<>) null) |>
Seq.iter
(fun (s : string) ->
let arr = s.Split([|' '|])
let a = int64 arr.[0]
let b = int64 arr.[1]
/// solve test case and output answer
printfn "%d" (abs (a - b))
)
0
I think that should give you enough info to solve the "which is greater" problem you're looking at. (Note that Console.Read only reads a single character, so it's not what you want for this problem. Instead, you probably want to read in the entire line, then split it into two strings at the blank space, then convert each of those strings into an integer. Coincidentally, the sample code I pasted above does something similar.)
I've got a problem in OCaml, I'm currently learning it but I'm quite a newbie still. I would like to make a function which is returning true if the string is empty or contains only whitespace and in the same time remove any occurence of begin and end.
I tried already this:
let isEmptyString s =
let rec empty i =
if i < 0 then true
else
let c = String.get s i in
if c = ' ' || c = '\009' then empty (pred i)
else false
in
s = Str.global_replace( Str.regexp "begin") "" s;
s = Str.global_replace( Str.regexp "end") "" s;
empty (pred (String.length s))
But obviously, this function is not working as I would like it because I obtain still begin in Formula.importNrAgentsFormula after calling it... Here is my way to call it :
while true do
let input = read_line () in
if not (isEmptyString input) then
let (nr, f) = Formula.importNrAgentsFormula input in
incr counter;
flush stdout;
match choice with
| "graph" -> printRes (Graph.isSat ~verbose:verb nr f)
| _ -> printUsage ()
else ()
done
If someone with more experiences in OCaml could spot and explain to me the error, I would be glad :)
Thanks in advance,
Best Regards.
I suggest you let your function isEmptyString (isBlankString rather?) do what it is supposed to do (just check if it contains only whitespaces or nothing), it should not modify the original string. You can do this in your loop:
while true do
let input = read_line () in
let input = Str.global_replace( Str.regexp "begin") "" input in
let input = Str.global_replace( Str.regexp "end") "" input in
if not (isEmptyString input) then
...
Edit: Sorry for the late edit, here is some additional information on your error:
If you run your function in OCaml, you will see this warning:
Warning 10: this expression should have type unit.
on the line of s = Str.global_replace( Str.regexp "begin") "" s;. That is because the = operator in OCaml is not the assignment operator in this case but the equality operator, so on this line you simply compare your two values and return a boolean. Since OCaml expects e1 in e1;e2 to return unit, you get this warning.
In OCaml, values of variables are immutable, so you can:
Use another variable as #Jason suggests: let t = Str.global_replace( Str.regexp "begin") "" s
"shadow" the old value as I suggest above: let s = Str.global_replace( Str.regexp "begin") "" s
Use a reference (a pointer to a location in memory): let s = ref "before" in s := "after", you can then access the value pointed by the reference with the !operator: !s. However, if you are learning functional programming, I suggest you try not to use any imperative features of OCaml at the beginning to discover this new paradigm and its possibilities.
As I am at work I don't have utop with me, but just from first glance, in your first one, the documentation says:
val global_replace : regexp -> string -> string -> string
That means you don't need a ";" as that is for when functions return unit and is syntactic sugar for something like
let () = print_endline("foobar")
Additionally, you need to use a let statement as you cannot just reassign the value of s. I don't recommend shadowing the variable as that's generally bad practice in functional programming. Use something like:
let t = (Str.global_replace( Str.regexp "begin") "" s)
Also, your function does two different things. The helper recursive function you wrote returns true and false which is good (I'm assuming it works). What you ultimately use it for however is what you're returning. Therefore, for the first function are you aren't really returning the string if "begin" and "end"s have been replaced. Therefore you should have the end output of your function actually a tuple of type (bool,string). Then you can match on it when you call it (e.g.
let b,s = isEmptyString "foobar" in
if not b then:
rest of your code
I believe you have the right idea for your function though.
Also in your second function is there a way for you to not use any while loops and counters? (Also hopefully your counter is implemented with references otherwise you won't have anything global). I would suggest retrying the place where you call your first function as loops and counters are core to imperative programming and not functional (which is what makes OCaml so
fun
:). If not, it's fine sometimes there are just things you can't really do in OCaml without using its imperative features. Let me know if those suggestions don't work.
I need to create a function that basically works like this :
insert_char("string" 'x') outputs "sxtxrxixnxg".
So here is my reasoning :
Create a list with every single character in the string :
let inserer_car(s, c) =
let l = ref [] in
for i = 0 to string.length(s) - 1 do
l := s.[i] :: !l
done;
Then, I want to use List.map to turn it into a list like ['s', 'x', 't', 'x' etc.].
However, I don't really know how to create my function to use with map. Any help would be appreciated!
I'm a beginner in programming and especially in ocaml! so feel free to assume I'm absolutely ignorant.
If you were using Core, you could write it like this:
open Core.Std
let insert_char s c =
String.to_list s
|> (fun l -> List.intersperse l c)
|> String.of_char_list
Or, equivalently:
let insert_char s c =
let chars = String.to_list s in
let interspersed_chars = List.intersperse chars c in
String.of_char_list interspersed_chars
This is just straightforward use of existing librariies. If you want the implementation of List.intersperse, you can find it here. It's quite simple.
A map function creates a copy of a structure with different contents. For lists, this means that List.map f list has the same length as list. So, this won't work for you. Your problem requires the full power of a fold.
(You could also solve the problem imperatively, but in my opinion the reason to study OCaml is to learn about functional programming.)
Let's say you're going to use List.fold_left. Then the call looks like this:
let result = List.fold_left myfun [] !l
Your function myfun has the type char list -> char -> char list. In essence, its first parameter is the result you've built so far and its second parameter is the next character of the input list !l. The result should be what you get when you add the new character to the list you have so far.
At the end you'll need to convert a list of characters back to a string.
I have a question I am rather unsure about.
My questions is as follows
let myFunc (text:string) (times:int) = ....
What I want this function to do is put the string together as many times as specified by the times parameter.
if input = "check " 3 I want the output string = "check check check"
I have tried with a loop, but couldn't seem to make it work.
Anyone?
Actually the function is already in String module:
let multiply text times = String.replicate times text
To write your own function, an efficient way is using StringBuilder:
open System.Text
let multiply (text: string) times =
let sb = new StringBuilder()
for i in 1..times do
sb.Append(text) |> ignore
sb.ToString()
If you want to remove trailing whitespaces as in your example, you can use Trim() member in String class to do so.
A variation on pad's solution, given that it's just a fold:
let multiply n (text: string) =
(StringBuilder(), {1..n})
||> Seq.fold(fun b _ -> b.Append(text))
|> sprintf "%O"
If you want a pure functional "do-it-yourself" version for F# learning purposes, then something like the following snippet will do:
let myFunc times text =
let rec grow result doMore =
if doMore > 0 then
grow (result + text) (doMore- 1)
else
result
grow "" times
Here is the test:
> myFunc 3 "test";;
val it : string = "testtesttest"
Otherwise you should follow the pointer about the standard F# library function replicate given in pad's answer.
String.replicate already provides the functionality you're looking for.
If for some reason you want the arguments reversed, you can do it as follows:
(* A general function you should add to your utilities *)
let flip f a b = f b a
let myFunc = flip String.replicate
In a simple recursive fashion:
let rec dupn = function
|s,1 -> s
|s,n -> s ^ dupn(s, n-1)
I'm trying to parse command line arguments in an F# application. I'm using pattern matching over parameters list to accomplish it. Something like:
let rec parseCmdLnArgs =
function
| [] -> { OutputFile = None ; OtherParam = None }
| "/out" :: fileName :: rest -> let parsedRest = parseCmdLnArgs rest
{ OutputFile = Some(fileName) with parsedRest }
The problem is I want to make "/out" match case insensitive while preserving the case of other stuff. That means I can't alter the input and match the lowercase version of the input against it (this will lose the fileName case information).
I have thought about several solutions:
Resort to when clauses which is less than ideal.
Match a tuple each time, the first would be the actual parameter (which I'll just save for further processing and will wildcard match it) and the second would be the lowercased version used in such matchings. This looks worse than the first.
Use active patterns but that looks too verbose. I'll have to repeat things like ToLower "/out" before every item.
Is there a better option/pattern for doing these kind of stuff? I think this is a common problem and there should be a good way to handle it.
I quite like your idea of using F# active patterns to solve this. It is a bit more verbose than using pre-processing, but I think it's quite elegant. Also, according to some BCL guidelines, you shouldn't be using ToLower when comparing strings (ignoring the case). The right approach is to use OrdinalIgnoreCase flag. You can still define a nice active pattern to do this for you:
open System
let (|InvariantEqual|_|) (str:string) arg =
if String.Compare(str, arg, StringComparison.OrdinalIgnoreCase) = 0
then Some() else None
match "HellO" with
| InvariantEqual "hello" -> printfn "yep!"
| _ -> printfn "Nop!"
You're right that it's more verbose, but it nicely hides the logic and it gives you enough power to use the recommended coding style (I'm not sure how this could be done using pre-processing).
I might do some pre-processing to allow for either "-" or "/" at the beginning of keywords, and to normalize the case:
let normalize (arg:string) =
if arg.[0] = '/' || arg.[0] = '-' then
("-" + arg.[1..].ToLower())
else arg
let normalized = args |> List.map normalize
It's perhaps not ideal, but it's not like any user is going to have enough patience to type so many command-line parameters that looping through them twice is noticeably slow.
You can use guards to match your deal:
let rec parseCmdLnArgs =
function
| [] -> { OutputFile = None ; OtherParam = None }
| root :: fileName :: rest when root.ToUpper() = "/OUT" -> let parsedRest = parseCmdLnArgs rest
{ OutputFile = Some(fileName) with parsedRest }
Ran into this looking for a solution to a similar issue, and while Tomas' solution works for individual strings, it doesn't help with the original issue of pattern matching against lists of strings. A modified version of his active pattern allows matching lists:
let (|InvariantEqual|_|) : string list -> string list -> unit option =
fun x y ->
let f : unit option -> string * string -> unit option =
fun state (x, y) ->
match state with
| None -> None
| Some() ->
if x.Equals(y, System.StringComparison.OrdinalIgnoreCase)
then Some()
else None
if x.Length <> y.Length then None
else List.zip x y |> List.fold f (Some())
match ["HeLlO wOrLd"] with
| InvariantEqual ["hello World";"Part Two!"] -> printfn "Bad input"
| InvariantEqual ["hello WORLD"] -> printfn "World says hello"
| _ -> printfn "No match found"
I haven't been able to figure out how to make it match with placeholders properly to do | InvariantEqual "/out" :: fileName :: rest -> ... yet, but if you know the entire contents of the list, it's an improvement.