Haskell recursive nextWord function - haskell

I wanted to implement a function nextWord which given a list of characters s (i.e. a String)
returns a pair consisiting of the next word in s and the remaining characters in s after the
first word has been removed. I tried this and I got error messages:
nextWord :: String -> (String, String)
nextWord [] = ([],[])
nextWord (next:rest)
| isSpace next = ([],rest)
| otherwise = next : [restWord,restString]
where
(restWord,restString) = nextWord next
However, when I looked at the solution I noticed that there is a big resemblance:
nextWord :: String -> ( String, String )
nextWord [] = ( [], [] )
nextWord ( next : rest )
| isSpace next = ([], rest)
| otherwise = let (restWord, restString) = nextWord rest
in (next : restWord, restString)
which works perfectly.
My question is first of all, why didn't my function work? I know I'm doing something wrong when defining restWord / restString.
Also, in the solution, how does the last line work?
next : restWord , restString
restWord, restString isn't a list, therefore how does the cont work here?
Thanks!

In the function you wrote, you sometimes return ([],rest), a tuple, and other times return next : [restWord,restString], a list. Those two types are incompatible, and so the function can't be typed.
In the working function, (next : restWord, restString) is a tuple: its fst is next:restWord and its snd is restString. This way, the function's return value is always a tuple, so the types line up.

Related

How convert first char to lowerCase

Try to play with string and I have string like: "Hello.Word" or "stackOver.Flow"
and i what first char convert to lower case: "hello.word" and "stackOver.flow"
For snakeCase it easy we need only change UpperCase to lower and add '_'
but in camelCase (with firs char in lower case) i dont know how to do this
open System
let convertToSnakeCase (value:string) =
String [|
Char.ToLower value.[0]
for ch in value.[1..] do
if Char.IsUpper ch then '_'
Char.ToLower ch |]
Who can help?
module Identifier =
open System
let changeCase (str : string) =
if String.IsNullOrEmpty(str) then str
else
let isUpper = Char.IsUpper
let n = str.Length
let builder = new System.Text.StringBuilder()
let append (s:string) = builder.Append(s) |> ignore
let rec loop i j =
let k =
if i = n (isUpper str.[i] && (not (isUpper str.[i - 1])
((i + 1) <> n && not (isUpper str.[i + 1]))))
then
if j = 0 then
append (str.Substring(j, i - j).ToLower())
elif (i - j) > 2 then
append (str.Substring(j, 1))
append (str.Substring(j + 1, i - j - 1).ToLower())
else
append (str.Substring(j, i - j))
i
else
j
if i = n then builder.ToString()
else loop (i + 1) k
loop 1 0
type System.String with
member x.ToCamelCase() = changeCase x
printfn "%s" ("StackOver.Flow".ToCamelCase()) //stackOver.Flow
//need stackOver.flow
I suspect there are much more elegant and concise solutions, I sense you are learning functional programming, so I think its best to do stuff like this with recursive function rather than use some magic library function. I notice in your question you ARE using a recusive function, but also an index into an array, lists and recursive function work much more easily than arrays, so if you use recursion the solution is usually simpler if its a list.
I'd also avoid using a string builder, assuming you are learning fp, string builders are imperative, and whilst they obviously work, they wont help you get your head around using immutable data.
The key then is to use the pattern match to match the scenario that you want to use to trigger the upper/lower case logic, as it depends on 2 consecutive characters.
I THINK you want this to happen for the 1st char, and after a '.'?
(I've inserted a '.' as the 1st char to allow the recursive function to just process the '.' scenario, rather than making a special case).
let convertToCamelCase (value : string) =
let rec convertListToCamelCase (value : char list) =
match value with
| [] -> []
| '.' :: second :: rest ->
'.' :: convertListToCamelCase (Char.ToLower second :: rest)
| c :: rest ->
c :: convertListToCamelCase rest
// put a '.' on the front to simplify the logic (and take it off after)
let convertAsList = convertListToCamelCase ('.' :: (value.ToCharArray() |> Array.toList))
String ((convertAsList |> List.toArray).[1..])
The piece to worry about is the recusive piece, the rest of it is just flipping an array to a list and back again.

How do I get the index of empty lines in a string in Haskell using pattern matching without importing anything?

For example:
nLn "This\n\nis an\nexample\n\n" == [2,5,6]
nLn "" == [1]
I have tried this but it doesn't seem to be working, why is that?
nLn :: Integral a => String -> [a]
nLn "" = [1]
nLn (x:xs) = [n | n <- lineBr (x:xs)]
where
lineBr (x:y:xs)
|x == y && y =='\n' = 1
|otherwise = 1+ lineBr (y:xs)
lineBr [x] = 0
I have to admit that I don't completely get where you are going with your attempted solution. The reason that it doesn't work, i.e., that is gets rejected by the type checker, is that while your helper function lineBr returns a single number, it is used by nLn as if it returns a list, i.e., as the generating expression in a list comprehension.
Here's an implementation (with a simpler type and an arguably more descriptive name) that does the trick:
indicesOfEmptyLines :: String -> [Int]
indicesOfEmptyLines = go 1 True
where
go _ False "" = []
go i True "" = [i]
go i False ('\n' : cs) = go (i + 1) True cs
go i True ('\n' : cs) = i : go (i + 1) True cs
go i _ (c : cs) = go i False cs
The idea is to have the heavy lifting done by a helper function go that will iterate over the characters in the input string. The helper function takes two additional arguments: the index of the line that it is currently processing (I followed your example and used 1-based indexing) and a Boolean indicating whether the currently processed line can still be empty.
We consider five cases:
If we reach the end of the string and the current line is known not to be empty, we know we are done and we have no more indices to report. Hence, we produce the empty list.
If we reach the end of the string and the current line can still be empty (i.e., we have not encountered any characters on it yet), we know we are done and that the last line was in fact an empty line. Hence, we produce a singleton list containing the index of the last line.
If we encounter a newline character and the current line is known not to be empty, we advance the index, acknowledge that the next line can still be empty (as we have not encountered any characters on it yet), and we proceed by processing the remainder of the string.
If we encounter a newline character and the current line can still be empty, then we know that the current line is in fact empty and we prepend the current index to any indices that the recursive call to go will produce. We advance the index, acknowledge that the next line can still be empty, and we proceed by processing the remainder of the string.
If we encounter any other character than a newline, we know that the current line cannot be empty (hence, we pass False to the recursive call to go) and we proceed by processing the remainder of the string.
Seeing it in action:
> indicesOfEmptyLines "This\n\nis an\nexample\n\n"
[2,5,6]
> indicesOfEmptyLines ""
[1]

How to check if list of phrases exists in the text?

I have been trying to create a filter that checks if a phrase in a list of phrases exists in the text using recursive functions and match patterns, but somehow that does not seems to work... Maybe someone could give me hint why?
let rec matchTails (tail1 : string list) (tail2 : string list) =
match tail1, tail2 with
| h1::t1 , h2::t2 ->
if (h1=h2) then
matchTails t1 t2
else
false
| _, [] -> false
| [],_-> true
let rec check2 (textH: string) (textT: string list) (phrases: string list list) =
match phrases with
|[] -> ()
| h :: t ->
printfn "%s -- %s" (h.Head) (textH)
match h with
|x when x.Length = 1 && x.Head = textH ->
()
|x when x.Head = textH && (matchTails (textT) (x)) ->
printfn "%s" (x.Head)
| _ -> ()
check2 (textH) (textT) (t)
let rec check (phrases : string list list) (text:string list) =
match text with
| [] -> ()
| h :: t ->
check2 (h) (t) (phrases)
check phrases t
let p = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]
Function call: check p t
I have edited my question with fixing few mistakes, but however, with these lists the program is giving unit() as an output...
There are some hints:
matchTails returns incorrect result for
matchTails [ "asdf1" ] [ "asdf" ] => true
matchTails [ "asdf" ] [ "asdf"; "asdf1" ] => true
matchTails [ ] [ "" ] => true
I suspect it should return false in all these cases. Probably the implementation you want is:
let rec matchTails (phrase : string list) (text : string list) =
match phrase, text with
| h1 :: t1, h2 :: t2 -> if h1 = h2 then matchTails t1 t2
else false
| [ ], _ -> true
| _ -> false
let matchTails_test () =
if not (matchTails [ "" ] [ "" ]) then raise Exception()
...
check2 is not called recursively so only the first phrase is checked
check is not called recursively, it calls check2 and returns
Generally, try to decompose problem into smaller functions and test each of them separately. You are moving in right direction, what is missing is clarity of what the each of the functions should do and test cases.
Update:
Note that check2 does not really return any value (it returns unit). Also it functionality overlaps with matchTails - it checks the head with the first word in the phrase, it is what matchTails does anyway.
check also returns unit, () means unit.
So let's rewrite check:
let rec check (phrases : string list list) (text : string list) =
if phrases |> List.exists (fun ph -> matchTails ph text) then
true
else
match text with
| [] -> false
| _ :: tail -> check phrases tail
While the question has now been basically answered, I would like to point out that its division into sub-problems is already very sufficient; shockingly lacking are the associated testing, and some descriptive naming of the individual functions tackling each sub-problem.
What about naming (and testing) matchTails, check2 and check exemplarily like this?
let ps = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]
startsWithPhrase ["hello"; "and"] t
containsPhrase ["free"; "cash"] t
containsAnyPhrase ps t
Spoiler:
let rec startsWithPhrase phrase text =
match phrase, text with
| h1::t1, h2::t2 when h1 = h2 -> startsWithPhrase t1 t2
| [], _-> true
| _ -> false
let rec containsPhrase phrase text =
startsWithPhrase phrase text ||
match text with
| _::tl -> containsPhrase phrase tl
| [] -> false
let rec containsAnyPhrase phrases text =
match phrases with
| h::tl ->
containsPhrase h text ||
containsAnyPhrase tl text
| [] -> false
It may be much easier to stay completely with high-level functions, each in place of one recursive loop. Albeit here with a slighty different approach, dividing your haystack into needle-sized slices and comparing each of them with a given phrase.
let containsPhraseHL phrase text =
Seq.windowed (List.length phrase) text
|> Seq.exists (Seq.forall2 (=) phrase)
containsPhraseHL ["free"; "cash"] t
let containsAnyPhraseHL phrases text =
List.exists (fun phrase -> containsPhraseHL phrase text) phrases
containsAnyPhraseHL ps t

String Matching with newline character in Haskell

Here I am trying to find the index of '-' followed by '}' in a String.
For an input like sustringIndex "abcd -} sad" it gives me an output of 10
which is giving me the entire string length.
Also if I do something like sustringIndex "abcd\n -} sad" it gives me 6
Why is that so with \n. What am I doing wrong. Please correct me I'm a noob.
substrIndex :: String -> Int
substrIndex ""=0
substrIndex (s:"") = 0
substrIndex (s:t:str)
| s== '-' && t == '}' = 0
| otherwise = 2+(substrIndex str)
Your program has a bug. You are checking every two characters. But, what if the - and } are in different pairs, for example S-}?
It will first check S and - are equal to - and } respectively.
Since they don't match, it will move on with } alone.
So, you just need to change the logic a little bit, like this
substrIndex (s:t:str)
| s == '-' && t == '}' = 0
| otherwise = 1 + (substrIndex (t:str))
Now, if the current pair doesn't match -}, then just skip the first character and proceed with the second character, substrIndex (t:str). So, if S- doesn't match, your program will proceed with -}. Since we dropped only one character we add only 1, instead of 2.
This can be shortened and written clearly, as suggested by user2407038, like this
substrIndex :: String -> Int
substrIndex [] = 0
substrIndex ('-':'}':_) = 0
substrIndex (_:xs) = 1 + substrIndex xs

split string logic error

Hello this function should take a String and return a list of Strings split at the Char c. I should define some helper functions but currently the user must initialize args that should be hidden from them.
xs = output list, i = start index for substr, j = end index for substr
example: split "123,456,789" ',' [] 0 0
should yield ["789", "456", "123"]
split s c xs i j =
if j == length s
then (subStr s i j) : xs
else if head (drop j s) == c
then split s c (subStr s i j : xs) (j + 1) (j + 1)
else split s c xs i (j + 1)
subStr s i j = take j(drop i s)
When i apply the function with the following args: split "123,456,789" ',' [] 0 0
I'm getting the result: ["789", "456,789", "123"]
I already mentioned this on your other post, but the issue with this is your subStr function. If you change it to subStr s i j = take (j-i) (drop i s) it should work. And if that's all you want, great. But it could be written more clearly and easily using takeWhile, or using split from data.Text.
Also, type signatures please. (Although I do appreciate that you defined the inputs this time.) Not only do they make it easier for us to help, you can often solve your own problems in the process of figuring them out.

Resources