I cannot find any examples of String.iter so I've been looking at Seq.iter and Array.iter's examples and trying to apply it to chars in a string but I just can't get it right. Could somebody please give me an example on how to use String.iter. I need to do functions with each char in a string.
Here is what I was doing previously but I know this can be improved on and made way more efficient, I don't want to have to convert a string to a char list just to cycle through it.
let chars = [ 'a'; 'b'; 'c' ]
let mutable result = 0
for c in chars do
match c with
| 'a' -> (result <- result + 1)
| 'b' -> (result <- result + 2)
| 'c' -> (result <- result + 3)
| _ -> printfn "test"
printfn "result of %A is %d" chars result
System.Console.ReadKey() |> ignore
First of all, F# has type string (which is a .NET type) and this is distinct type from char list (which is a functional F# list of characters). In your example, you are creating a list of characters, so you can best process it using functions from the List module.
Regarding iteration - in your case, you are accumulating some state and so iter is not the operation you need (iter is used for performing some imperative action for each element).
To solve your specific problem, the nicest option is to use List.sumBy:
let result = chars |> List.sumBy (fun c ->
match c with
| 'a' -> 1
| 'b' -> 2
| 'c' -> 3
| _ ->
printfn "test"
0 )
The sumBy function sums the numbers returned for each element and so you just need to return 1, 2 or 3. In the remaining case, we print (leaving the same side-effect) and return 0 because we just want to keep the same sum.
More generally, you could use List.fold which lets you accumulate results as you iterate over the list:
let result = chars |> List.fold (fun result c ->
match c with
| 'a' -> result + 1
| 'b' -> result + 2
| 'c' -> result + 3
| _ ->
printfn "test"
result ) 0
In all of these, you can replace List. with Seq. because functions in Seq. work on any sequence (lists, arrays, strings, etc.). This might be a bit slower, but that's typically not an issue. The String module has fewer functions and you could use it if you defined your input as "abc" rather than ['a';'b';'c']
EDIT: To answer the questions in comments, if you can use Seq.sumBy directly on a string and you can use int to convert a character to its numerical code, so you can use that to eliminate pattern matching (this handles all characters in the same way, you might want to filter invalid ones out using Seq.filter first, depending on what logic you're implementing):
let str = "abc"
let result = str |> Seq.sumBy (fun c -> (int c) - 96)
Related
First of all, I want to say that I'm very very inexperienced with Haskell, and I know that I have done something (or multiple things) terribly wrong, been struggling for hours but I can't seem to find it.
power :: Int -> Int -> Int
power x y | y == 0 = 1
| x == 0 = 0
list = replicate y x
foldr (*) x list
main = print $ power 3 5
Error most of the time is either x and y not being passed to the replicate function or that foldr is a naked function, I understand what they both mean but have no idea on how I can pass the variables or come up with a solution.
You here created four functions: power, list, foldr and main. But you use variables x and y in the definition of the list function.
You can work with a where clause to specify subexpressions, for example:
power :: Int -> Int -> Int
power x y | y == 0 = 1
| x == 0 = 0
| otherwise = foldr (*) 1 list
where list = replicate y x
or perhaps more elegant with pattern matching:
power :: Int -> Int -> Int
power 0 _ = 0
power x y = foldr (*) 1 (replicate y x)
main = print $ power 3 5
Here we can also eliminate the case for x0, since our foldr starts working with 1, not x.
This algorithm is however not very efficient, since it is linear in the value of y. By checking recursively if the exponent is even or odd, you can make it faster. I leave this as an exercise.
You were very close! The main things that need to be fixed are:
When writing a definition with guards, the “fallback” case needs to be a guard as well, conventionally written with otherwise.
Recall that a definition without guards looks like this, with one left side (a name and parameter patterns/names) and one right side (an expression):
name patterns = expression
With guard conditions, there is one right-hand side for each guard:
name patterns | condition1 = expression1
| condition2 = expression2
…
| otherwise = expressionn
otherwise is really just an alias for True, that is, such a guard always matches. The only thing special about otherwise is that the compiler uses it as a hint when analysing whether a pattern match covers all possible cases.
In order to define a variable list, local to the definition of power, using the parameters x and y, you need to use either a let…in… expression, that is, let block in expression, or a where clause, equation where block. A block is a series of items (in this case, local definitions) which must all be written starting at the same column of indentation, or be delimited by explicit curly braces {…} and semicolons ;.
Using let…in… follows the structure of your original code pretty closely. I will adjust the indentation style to avoid needing to align anything, by putting a newline and a constant amount of indentation instead.
power :: Int -> Int -> Int
power x y
| y == 0 = 1
| x == 0 = 0
| otherwise = let
list = replicate y x
in foldr (*) x list
main :: IO ()
main = print $ power 3 5
Attaching a where clause to an equation is slightly more common than using a let…in… expression on the right side of an equation.
power :: Int -> Int -> Int
power x y
| y == 0 = 1
| x == 0 = 0
| otherwise = foldr (*) x list
where
list = replicate y x
main :: IO ()
main = print $ power 3 5
Note that in this case, there is a slight difference: the variable list is visible in all of the right-hand sides, although we only use it in one of them. With let list = … in e, list is only defined within e. In general, it’s helpful for readability to keep the scope of a variable as small as possible, although you can certainly go overboard:
a = …
where
b = …
where
c = …
where
d = …
-- If you see this much nesting, rethink!
If you run into issues with alignment and indentation, you can always use explicit delimiters instead. The code I wrote is equivalent to the following.
power :: Int -> Int -> Int; -- Begin ‘power’ signature.
power x y
| y == 0 = 1
| x == 0 = 0
| otherwise = let { -- Begin ‘let’ block.
list = replicate y x; -- End ‘list’ equation.
} in foldr (*) x list; -- End ‘let’ block, then end ‘power’ equation.
main :: IO (); -- Begin ‘main’ signature.
main = print $ power 3 5; -- End ‘main’ equation.
Or similarly with where { … }.
I am new to Haskell and I am currently learning it in school. I got a school task where I have to decode a message that contain certain patterns but I have got no idea how to do this.
The pattern looks something like this: If a letter has a consonant followed by the character 'o' and then once again followed by the same consonant as before it should replace that substring ("XoX" where X is a consonant) with only the consonant. For example if I decode the string "hohejoj" it should return "hej". Sorry if I am explaining this poorly but I think you understand.
This is the code I have so far (but it doesn't work):¨
karpsravor :: String->String
karpsravor s = karpsravor_help s ""
where karpsravor_help s res
|s == "" && (last res) == 'o' = (init res)
|s==""=res
|otherwise = karpsravor_help (drop 3 s) (res ++ (consDecode (take 3 s)))
consDecode :: String->String
consDecode a
|(length a) < 3 = ""
|a == [(head a)]++"o"++[(head a)] = [(head a)]
|otherwise = a
The code is completely broken and poorly written (dumb method) but I have no other idea for how to solve this. Please help!
Pattern match to find occurrences of 'o'. I.e., use
karpsravorhelp (a:'o':b:rest) res = ...
You can't have a:'o':a:rest in the above, you can't pattern match for equality; you'll need to use a guard to make sure that a == b:
karpsravorhelp (a:'o':b:rest) res
| a == b = ...
| otherwise = ...
You'll also have to make sure a and b are consonants, which will just be an 'and' condition for the first guard. For the otherwise condition, make sure that the recursive call calls (b:rest) since you could have something like a:'o':b:'o':b:....
Also make sure to match for two other patterns:
Empty List, []
x:rest, which must go after the above pattern; this way, it will first attempt to match on the a:'o':b:rest pattern, and if that's not there, just take the next letter.
One way to do it would be with unfoldr from Data.List. You can use a case expression to pattern match on a : 'o' : b : rest, and then check that a and b are equal and not vowels using a guard |. Then just include the base cases for when the pattern doesn't match.
notVowel :: Char -> Bool
notVowel = (`notElem` "aeiouAEIOU")
karpsravor :: String -> String
karpsravor = unfoldr $ \str -> case str of
a : 'o' : b : rest
| a == b && notVowel a -> Just (a, rest)
a : rest -> Just (a, rest)
"" -> Nothing
Was reading monadplus chapter of haskell wiki book: https://en.wikibooks.org/wiki/Haskell/MonadPlus
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise = do
let (c:_) = s
if [c] == show i then Just i else Nothing
"The do-block assures that any failed pattern match will result in returning Nothing."
However, when I tried digit 1 "", it produces irrefutable runtime error, instead of "Nothing".
I can get around it using (c:_) <- return s. It would be great if someone more experienced in haskell could confirm/clarify on this.
The code in wikibooks does not account for the case when the input string is empty. When the line let (c:_) = s is executed and s is empty, it will cause a failure in the pattern matching and an exception will be thrown. Your suggestion (c:_) <- return s is actually quite similar to the one used, except for one difference; when the pattern matching in a monadic bind (i.e. <-) fails, then the fail method of the monad will be called. Now, in the Maybe monad, fail is defined to always return Nothing,so it will cause the whole do block to return Nothing. One thing I don't like about using your suggestion is that I personally don't consider using fail to be the most elegant solution and I would prefer to use a case expression in the case:
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise =
case s of
c:_ | [c] == show i -> Just i
_ -> Nothing
In fact, as you can see, we don't need to use a do block at all.
Finally, here's a more compact version of the above code:
digit :: Int -> String -> Maybe Int
digit i s | 0 <= i, i <= 9, c:_ <- s, [c] == show i = Just i
| otherwise = Nothing
I need help with an exercise. I'm trying to write a function called "refer" that will take a list of novels and any given text with citations ([n]) and will return that text with the citations replaced by the novel's name.
refer will have the following signature of:
refer :: [(String, String, Int)] -> String -> String
For example, this is how it will be ran:
> refer [("author1", "novel1", 1999),("author2", "novel2", 2000)] txt
> "novel1(author1, 1999) and novel2(author2, 2000) are my favorite books of all time, but I like novel2(author2, 2000) the most!"
I wrote a function called, txt, which will show my text that I will use.
txt :: String
txt = "[1] and [2] are my favorite books of all time, but I like [2] the most!"
I wrote a helper function called, format, which will help me format the novels from ("author1", "novel1", 1999) to "novel1(author1, 1999)"
format :: (String, String, Int) -> String
format (name, novel, yearInt) = novel ++ " (" ++ name ++
", " ++ (show yearInt) ++ ")"
WHAT I THINK I NEED TO DO:
Step 1: I need to use words to break the input into a list of strings.
Step 2: I should make a helper function to parse through the list and if I find a citation, I should use format to replace that citation and recursively parse through the rest of the list until I've checked everything.
Step 3: Make a helper function to convert the string representation of the citation number into an Int (possibly, unwords) since I have to replace the citation with its corresponding element in the given list.
Step 4: Then I need to use rewords to turn my updated list back into a string.
WHAT I HAVE SO FAR:
refer :: [(String, String, Int)] -> String -> String
refer [] "" = ""
refer books txt = [string'| y <- words txt, ........... ]
-- I'm trying to say that I want to take the inputted list of
-- novels and text and turn them all into strings and store
-- them into y which will be represented by string'. I am not
-- sure what to do after this.
You could use words, but then you lose information about the white space between the words - i.e. words "a b" equals words "a b". Maybe this is not important, but it is something to keep in mind.
Without providing the exact solution, here is a function which replaces a with a' and b with b' in a list:
replace a a' b b' [] = [] -- base case
replace a a' b b' (x:xs) = c : replace a a' b b' xs
where c = if x == a then a' else if x == b then b' else x
Perhaps you can figure out how to adapt this to your problem.
Note also that this function may be written using map:
replace a a' b b' xs = map f xs
where f x = if x == a then a' else if x == b then b' else x
Another approach to this kind of string processing is to pattern match against the characters. Here is a function which removes all occurrences of "cat" from a string:
removeCat :: String -> String
removeCat ('c':'a':'t':rest) = rest -- "cat" found so remove it
removeCat (x:rest) = x : removeCat rest
If this is for a homework problem please don't copy verbatim.
It's easier to solve the generic problem.
First, you need a replace function to replace a substring. A straightforward implementation can be
replace :: String -> String -> String -> String
replace old new [] = []
replace old new input = if (take n input == old) then new++(recurse n)
else (take 1 input)++(recurse 1)
where n = length old
recurse k = replace old new $ drop k input
tries to match the "old" from the beginning of input and if matched replace and skip the length of old, if not matched move one position and repeat.
So far so good, this will replace all occurrences of "old" to "new". However, you need multiple different replacements. For that let's write another function. To minimize validations assume we paired all replacements.
replaceAll :: [(String,String)] -> String -> String
replaceAll [] input = input
replaceAll ((old,new):xs) input = replaceAll xs $ replace old new input
You can make the top level signature better by defining a type such as
type Novel = (String,String,Int)
finally,
refer :: [Novel] -> String -> String
refer [] text = text
refer ns text = replaceAll p text
where p = [ ("["++show i++"]",format n) | (i,n) <- zip [1..] ns]
notice that the citation input is derived from the position of the Novels.
In F# I want to transform a list of chars into a string. Consider the following code:
let lChars = ['a';'b';'c']
If I simply do lChars.ToString, I get "['a';'b';'c']". I'm trying to get "abc". I realize I could probably do a List.reduce to get the effect I'm looking for but it seems like there should be some primitive built into the library to do this.
To give a little context to this, I'm doing some manipulation on individual characters in a string and when I'm done, I want to display the resulting string.
I've tried googling this and no joy that way. Do I need to just bite the bullet and build a List.reduce expression to do this transformation or is there some more elegant way to do this?
Have you tried
System.String.Concat(Array.ofList(lChars))
How many ways can you build a string in F#?
Here's another handful:
let chars = ['H';'e';'l';'l';'o';',';' ';'w';'o';'r';'l';'d';'!']
//Using an array builder
let hw1 = new string [|for c in chars -> c|]
//StringBuilder-Lisp-like approach
open System.Text
let hw2 =
string (List.fold (fun (sb:StringBuilder) (c:char) -> sb.Append(c))
(new StringBuilder())
chars)
//Continuation passing style
let hw3 =
let rec aux L k =
match L with
| [] -> k ""
| h::t -> aux t (fun rest -> k (string h + rest) )
aux chars id
Edit: timings may be interesting? I turned hw1..3 into functions and fed them a list of 500000 random characters:
hw1: 51ms
hw2: 16ms
hw3: er... long enough to grow a beard? I think it just ate all of my memory.
Didn't see this one here, so:
let stringFromCharList (cl : char list) =
String.concat "" <| List.map string cl
"" is just an empty string.
FSI output:
> stringFromCharList ['a'..'d'];;
val it : string = "abcd"
EDIT:
Didn't like this syntax coming back to this so here's a more canonically functional one:
['a'..'z'] |> List.map string |> List.reduce (+)
['a';'b';'c'] |> List.fold_left (fun acc c -> acc ^ (string c)) ""
Edited:
Here is yet another funny way to do your task:
type t =
| N
| S of string
static member Zero
with get() = N
static member (+) (a: t, b: t) =
match a,b with
| S a, S b -> S (a+b)
| N, _ -> b
| _, N -> a
let string_of_t = function
|N -> ""
|S s -> s
let t_of_char c = S (string c)
['a'; 'b'; 'c'] |> List.map t_of_char |> List.sum |> string_of_t
Sadly, just extending System.String with 'Zero' member does not allow to use List.sum with strings.
Edited (answer to Juilet):
Yes, you are right, left fold is slow. But i know more slow right fold :) :
#r "FSharp.PowerPack"
List.fold_right (String.make 1 >> (^)) ['a';'b';'c'] ""
and of course there is fast and simple:
new System.String(List.to_array ['1';'2';'3'])
And i used 'sprintf' seems to me easier:
let t = "Not what you might expect"
let r = [ for i in "aeiou" -> i]
let q = [for a in t do if not (List.exists (fun x -> x=a) r) then yield a]
let rec m = function [] -> "" | h::t -> (sprintf "%c" h) + (m t)
printfn "%A" (m q)
The following solution works for me:
let charList = ["H";"E";"L";"L";"O"]
let rec buildString list =
match list with
| [] -> ""
| head::tail -> head + (buildString tail)
let resultBuildString = buildString charList
[|'w'; 'i'; 'l'; 'l'|]
|> Array.map string
|> Array.reduce (+)
or as someone else posted:
System.String.Concat([|'w'; 'i'; 'l'; 'l'|])