I need a function that take a string and a char , it slides the string and if it found the char return TRUE else FALSE.
This is my start point:
let rec check s a = match s with
"" -> false
| x::xs -> if x = a then true else check xs a ;;
I can’t use the library function of caml light (like index_char)
Thanks for help!
I will leave the explanation of how it works to you, this is my solution:
strobel#suse131:~> rlwrap camllight
> Caml Light version 0.75
let findchar c s =
let len = string_length s in
let rec f1 i s =
if i = len then false
else if s.[i]=c then true else f1 (succ i) s in
f1 0 s
;;
findchar : char -> string -> bool = <fun>
#let s = "this is the searched string";;
s : string = "this is the searched string"
#findchar `a` s;;
- : bool = true
#findchar `y` s;;
- : bool = false
Additional exercises:
could we leave out parameter s in the f1 definition?
how do we call the usage / occurence of len in the body of f1?
Related
I need a method using List.fold that will count the number of vowels in a given string.
So far I have this method.
let vowels = ['a';'e';'i';'o';'u']
let isVowel =
fun c -> vowels |> List.contains c
let count =
String.filter isVowel
>> String.length
printfn "%A" (count "aaaa")
It works fine, but I cannot figure out how to make a List.fold one using the same isVowel method. Here is my try.
The code below does not work, its purpose is to reflect my idea. Since the fold method applies the isVowel() which returns a true/false on each char in the string, if the condition is true it will add 1 to the accumulator which is the 0 parameter. When I try to use if else insinde the anon function I get an error.
let isVowel x =
match x with
| 'a' -> true
| 'e' -> true
| 'i' -> true
| 'o' -> true
| 'u' -> true
| _ -> false
let countNumOfVowels =
List.fold (fun (isVowel) (x) -> x + 1) 0 ["aaaa"]
You are trying to fold a list but your source is actually a string.
A string can be interpreted as a sequence of chars if you use Seq.fold:
"abracadabra" |> Seq.fold (fun i c -> if isVowel c then i + 1 else i) 0
// val it : int = 5
This is what I was looking for. Thanks Gus!
let countNumOfVowels str =
List.fold (fun (x: int) (c: char) -> if (isVowel c) then x + 1 else x) 0 (Seq.toList str)
countNumOfVowels "Hello"
> countNumOfVowels "Hello";;
val it : int = 2
What I am trying to do is to remove duplicates of a specific given char in a string but letting the first char to remain. I.e:
let myStr = "hi. my .name."
//a function that gets a string and the element to be removed in the string
someFunc myStr "."
where someFunc returns the string showen as below:
"hi. my name"
It is easy to remove duplicates from a string, but is there a way to remove the duplicates but letting the first duplicated element remain in the string?
Here's one approach:
let keepFirst c s =
Seq.mapFold (fun k c' -> (c', k||c<>c'), k&&c<>c') true s
|> fst
|> Seq.filter snd
|> Seq.map fst
|> Array.ofSeq
|> System.String
let example = keepFirst '.' "hi. my .name."
let someFunc (str : string) c =
let parts = str.Split([| c |])
if Array.length parts > 1 then
seq {
yield Array.head parts
yield string c
yield! Array.tail parts
}
|> String.concat ""
else
str
Note that the character is given as char instead of a string.
let someFunc chr (str:string) =
let rec loop (a: char list) b = function
| [] -> a |> List.rev |> System.String.Concat
| h::t when h = chr -> if b then loop a b t
else loop (h::a) true t
| h::t -> loop (h::a) b t
loop [] false (str.ToCharArray() |> Array.toList)
Note that the character is given as char instead of a string.
Edit: Another way would be using regular expressions
open System.Text.RegularExpressions
let someOtherFunc c s =
let pat = Regex.Escape(c)
Regex.Replace(s, sprintf "(?<=%s.*)%s" pat pat, "")
Note that, in this case the character is given as string.
Edit 2:
let oneMoreFunc (c:char) (s:string) =
let pred = (<>) c
[ s |> Seq.takeWhile pred
seq [c]
s |> Seq.skipWhile pred |> Seq.filter pred ]
|> Seq.concat
|> System.String.Concat
When devising a function, think about gains from making its arguments generic. To pass state through the iteration, barring mutable variables, Seq.scan could be a weapon of choice. It folds into a tuple of new state and an option, then Seq.choose strips out the state and the unwanted elements.
In terms of functional building blocks, make it accept a predicate function 'a -> bool and let it return a function seq<'a> -> seq<'a>.
let filterDuplicates predicate =
Seq.scan (fun (flag, _) x ->
let p = predicate x in flag || p,
if flag && p then None else Some x ) (false, None)
>> Seq.choose snd
This can then easily reused to do other things as well, like 0 together with odd numbers.
filterDuplicates (fun i -> i % 2 = 0) [0..10]
// val it : seq<int> = seq [0; 1; 3; 5; ...]
Supplied with a call to the equality operator and fed into the constructor of System.String, you'll get near the signature you want, char -> seq<char> -> System.String.
let filterDuplicatesOfChar what s =
System.String(Array.ofSeq <| filterDuplicates ((=) what) s)
filterDuplicatesOfChar '.' "hi. my .name."
// val it : string = "hi. my name"
I have implemented a Table data type in haskell,but my minkey function which is supposed to return the smallest key seems not to give the right result. I am just wondering why..
module Table where
import Prelude hiding (init,read,length)
type Key = Int
type Value = String
errorvalue = "ERROR"
maxentries = 5
data Table = Empty | App(Key,Value,Table)
deriving Show
init :: Table
insert :: (Key,Value,Table) -> Table
isin :: (Key,Table) -> Bool
read :: (Key,Table) -> Value
empty :: Table -> Bool
delete :: (Key,Table) -> Table
update :: (Key,Value,Table) -> Table
length :: Table -> Int
full :: Table -> Bool
minkey::Table->Key
init = Empty
minkey(App(k,v,init))=k
minkey(App(k,v,t))= if k>minkey(t) then minkey(t) else k
insert(k,v,t) = if v == errorvalue then t
else if isin(k,t) then t
else if full(t) then t
else App(k,v,t)
isin(x,Empty) = False
isin(x,App(k,v,t)) = if x == k then True
else isin(x,t)
read(x,Empty) = errorvalue
read(x,App(k,v,t)) = if x == k then v
else read(x,t)
empty(Empty) = True
empty(App(k,v,t)) = False
delete(x,Empty) = Empty
delete(x,App(k,v,t)) = if x == k then t
else App(k,v,delete(x,t))
update(k,v,Empty) = Empty
update(k,v,App(k2,v2,t)) = if k == k2 then App(k,v,t)
else App(k2,v2,update(k,v,t))
length(Empty) = 0
length(App(k,v,t)) = 1 + length(t)
full(t) = if length(t) == maxentries then True
else False
In another script I initialized a table:
import Table
import Prelude hiding (init,read,length)
main :: IO ()
main = do
let k1 = 9
let k2 = 8
let k3 = 1
let k4 = 6
let k5 = 10
let v1 = "q"
let v2 = "a"
let v3 = "si"
let v4 = "se"
let v5 = "fu"
let i0 = init
let i1 = insert(k1,v1,i0)
let i2 = insert(k2,v2,i1)
let i3 = insert(k3,v3,i2)
let i4 = insert(k4,v4,i3)
let i5 = insert(k5,v5,i4)
let m = minkey(i5)
print m
print i5
When I print m the output is not 1 as I expected,but the last key imported to the table (in this case 10)
What am I doing wrong? Maybe the recursion?
minkey's init is regarded as argument name, not Empty, so pattern always matches on that line. Maybe GHC might have warned you as -Woverlapping-patterns.
If init can't be changed, then you may use case expression.
I want to remove a char in a string. but not all the elements of that char in a string. example. i want "|red|red|red|red|" to turn into "red|red|red|red" So I want to create a function that checks if the first and last index of a string is a certain char and remove it if its the case.
so far i have come up with something like this:
let rec inputFormatter (s : string) : string =
match s.[1] with
|'|'|','|'.'|'-' -> // something that replaces the char with "" in the string s
(inputFormatter s)
|_ -> match s.[(String.length s)] with
|"|"|","|"."|"-" -> // same as above.
(inputFormatter s)
|_ -> s
Can anyone help me figure out what i could write in my function? Ofcourse you are also welcome to come up with an etirely different function if you find that more conveniet.
thanks in advance!
let replace elem (str:string) =
let len = String.length str
if str.[0] = elem && str.[len-1] = elem then str.[1..len-2]
else str
Usage:
replace '|' "|red|red|red|red|"
// val it : string = "red|red|red|red"
And here's a version working with string instead of char:
let replace elem (str:string) =
let lens = String.length str
let lene = String.length elem
if lene <= lens && str.[0..lene-1] = elem && str.[lens-lene..lens-1] = elem then str.[lene..lens-lene-1]
else str
UPDATE
As Mark suggested a better option is re-using Trim
let replace (elem:string) (str:string) = str.Trim(elem.ToCharArray())
I didn't end up using Gutavo's fix but it was him that inspired me to fix my own function!
let rec theButcher (s : string) : string =
match s.[0] with
|'|'|','|'.'|'-'|' ' -> (theButcher s.[1..])
|_ -> match s.[(String.length s)-1] with
|'|'|','|'.'|'-'|' ' -> (theButcher s.[0..((String.length s)-2)])
|_ -> s
I am trying to write a function in haskell that would take an integer and return a concatenated (number of times the input) string
For Instance,
Input: 3
Output: hi1\nhi2\nhi3
main = do
let str = func 2 ""
putStrLn str
func :: Int -> String -> String
func i str = do
if i>(-1)
then do
str ++ "hi" ++ (show i)
func (i-1) str
else str
Thanking you!
This is a much more idiomatic solution than using if-else
a function that would take an integer and return a concatenated (number of times the input) string
func :: Int -> String -> String
func 0 s = ""
func n s = s ++ func (n - 1) s
main = putStrLn (func 3 "hi")
Output
hihihi
I wonder if 'logarithmic' solution is faster:
main = putStrLn $mul 7 "Hi"
mul :: Int -> String -> String
mul 0 _ = ""
mul 1 s = s
mul _ "" = ""
mul n s = let
(q, r) = n `quotRem` 2
s' = mul q s
in (if r == 1 then s else "") ++ s' ++ s'
The easiest way to make your code "work" (I'll explain the double quotes later) is to call func with the concatenated string as a parameter directly, without intermediate steps:
func :: Int -> String -> String
func i str = do
if i > (-1)
then func (i-1) (str ++ "hi" ++ (show i) ++ "\n")
else str
I also added the newline character to the output, which means that the last character of the result will be a new line. Therefore it is better to write
let str = func 2 ""
putStr str
That way you'll avoid an extra new line at the end.
I wrote "works" in double quotes in the first sentence, because my code prints
hi2
hi1
hi0
You need to modify func so that the lines are printed in reverse order. Hint: you can store the lines in a list and reverse the list at the end.
P.S. I'm not sure whether zero should be a valid suffix. If not, then you have to change the condition in your if statement.