Case Insensitive Pattern Matching over String Lists - string

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.

Related

How to handle simple inputs in Kattis with F#?

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.)

Haskell substring testing

When I use sub_string("abberr","habberyry") , it returns True, when obviously it should be False. The point of the function is to search for the first argument within the second one. Any ideas what's wrong?
sub_string :: (String, String) -> Bool
sub_string(_,[]) = False
sub_string([],_) = True
sub_string(a:x,b:y) | a /= b = sub_string(a:x,y)
| otherwise = sub_string(x,y)
Let me give you hints on why it's not working:
your function consumes "abber" and "habber" of the input stings on the initial phase.
Now "r" and "yry" is left.
And "r" is a subset of "yry". So it returns True. To illustrate a more simple example of your problem:
*Main> sub_string("rz","rwzf")
True
First off, you need to switch your first two lines. _ will match [] and this will matter when you're matching, say, substring "abc" "abc". Secondly, it is idiomatic Haskell to write a function with two arguments instead of one with a pair argument. So your code should start out:
substring :: String -> String -> Bool
substring [] _ = True
substring _ [] = False
substring needle (h : aystack)
| ...
Now we get to the tricky case where both of these lists are not empty. Here's the problem with recursing on substring as bs: you'll get results like "abc" being a substring of "axbxcx" (because "abc" will match 'a' first, then will look for "bc" in the rest of the string; the substring algorithm will then skip past the 'x' to look for "bc" in "bxcx", which will match 'b' and look for "c" in "xcx", which will return True.
Instead your condition needs to be more thorough. If you're willing to use functions from Data.List this is:
| isPrefixOf needle (h : aystack) = True
| otherwise = substring needle aystack
Otherwise you need to write your own isPrefixOf, for example:
isPrefixOf needle haystack = needle == take (length needle) haystack
As Sibi already pointed out, your function tests for subsequence. Review the previous exercise, it is probably isPrefixof (hackage documentation), which is just a fancy way of saying startsWith, which looks very similar to the function you wrote.
If that is not the previous exercise, do that now!
Then write sub_string in terms of isPrefixOf:
sub_string (x, b:y) = isPrefixOf ... ?? ???
Fill in the dots and "?" yourself.

OCaml : need help for List.map function

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.

Multiplying a string in F#

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)

F#: Remove the first N characters from a string?

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.

Resources