Haskell: Pig Latin - haskell

Question: The simple rule for translating into “Pig Latin” is to take a word that begins with a vowel and add "yay", while taking any word that be- gins with one or more consonants and transferring them to the back before appending "ay". For example, "able" becomes "ableyay" and "stripe" becomes "ipestray". Write a function that converts a string of letters into its Pig-Latin translation.
Implementation:
-- define function to detect vowel
isVowel :: Char -> Bool
isVowel c = elem c ['u','e','o','a','i']
-- define function Latin Pig
lp ::String -> String
lp str = if (isVowel (head str)) then do {str ++ "yay"}
else
do {
str ++ (head str)
tail str
lp str
}
Problem: So far I do not see any problem with my code (logic). Honestly this is my homework for an Intro to Haskell course. However the compiler gives me errors:
**Couldn't match expected type `t0 -> t1 -> t2 -> t3 -> [Char]'
with actual type `Char'
Expected type: [t0 -> t1 -> t2 -> t3 -> [Char]]
Actual type: String
In the first argument of `head', namely `str'
In the second argument of `(++)', namely
`(head str) tail str lp str'
Failed, modules loaded: none.**
What is wrong with my code?!

To begin, think about pattern matching.
Any not empty list can be define as x:xs, with,
x as head list
xs as tail list
then your code become,
-- define function Latin Pig
lp :: String -> String
lp [] = ""
lp (x:xs) = if (isVowel x) then str ++ "yay"
else ..... -- fill here
where str = (x:xs)
don't forget that the operator : is the constructor of list, for example,
'a':"bab" => "abab"
Keep in mind that a string is a list of char.
Furthermore, you can skip the where clause in the previous example, like this,
-- define function Latin Pig
lp :: String -> String
lp [] = ""
lp str#(x:xs) = if (isVowel x) then str ++ "yay"
else ..... -- fill here
Should be enough to help you.
Good luck

Here is another way of putting the pig latin rule:
if a word doesn't begin with a run of consonants, then the translation is the original word followed by "yay"
otherwise the translation is the rest of the word, followed by the initial run of consonants, followed by "ay"
This is easier to translate into Haskell.
(Actual Haskell code elided, as this is homework.)
You will find it helpful to combine your isVowel function with the break function from Data.List.

I'm not sure if it is part of your requirements to use recursion but here is my take on your task. You do not need to use the do monad to achieve what you want (unless that is an objective of the assignment?).
You might want to consider using pattern matching and guards instead of an if else block.
Also, like zurgl said, you can take advantage of matching the string like this: string#(x:xs) which will allow you to do work on the entire string while also using the head x and tail xs.
Note: All strings are lists.
Here is a quick example of what I suggested.
-- define function to detect vowel
isNotVowel :: Char -> Bool
isNotVowel c = notElem c ['u','e','o','a','i']
-- define function Latin Pig
lp :: String -> String
lp [] = []
lp p#(x:xs)
| not $ isNotVowel x = p++"yay"
| otherwise = let (constants, rest) = span isNotVowel p
in (rest++constants++"ay")
Have fun learning haskell!
Some nice resources for learning haskell:
Learn You A Haskell For Great Good
Real World Haskell

Kindly refer following code.
private static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException {
System.out.print("Enter sentence: ");
String sentence = getString();
String latin = pigLatinForSentence(sentence);
System.out.println(latin);
}
private static String pigLatinForSentence(String s) {
String latin = "";
int i = 0;
while (i < s.length()) {
while (i < s.length() && !isLetter(s.charAt(i))) {
latin = latin + s.charAt(i);
i++;
}
if (i >= s.length())
break;
int begin = i;
while (i < s.length() && isLetter(s.charAt(i))) {
i++;
}
int end = i;
latin = latin + pigWord(s.substring(begin, end));
}
return latin;
}
private static boolean isLetter(char c) {
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
}
private static String pigWord(String word) {
int split = firstVowelInSentence(word);
return word.substring(split) + "-" + word.substring(0, split) + "ay";
}
private static int firstVowelInSentence(String word) {
word = word.toLowerCase();
for (int i = 0; i < word.length(); i++)
if (word.charAt(i) == 'a' || word.charAt(i) == 'e' || word.charAt(i) == 'i' || word.charAt(i) == 'o'
|| word.charAt(i) == 'u')
return i;
return 0;
}
private static String getString() throws IOException {
return buf.readLine();
}
Hope this solution help you learn more detail about pig latin.

Related

Converting Strings into my own data type and vice versa

I'm working on a Haskell school assignment that asks me to convert a string to a self-defined data type : Position, which should only consist a char of (A-H) and an Int(1-4).(i.e A1, B3, H4)
Here is the function's usage:
toPosition gives Just the Position named by the string, or Nothing if the string is not a valid Position name.
Here is my try:
I defined the data type as:
data Position = Pos Char Int
Then my attempt on toPosition:
toPosition :: String -> Maybe Position
toPosition [] = Nothing
toPosition (x:xs)
| len(xs) == 1 = Loc x xs
| otherwise = Nothing
GHCi returning
'Not in scope: type constructor or class ‘Pos’'
Any ideas to fix this and validate the input so that it will only return a string when the input is a legal 'Position'?
---Update No.1----
I updated my code into the following:
type Position = Pos Char Int
toPosition :: String -> Maybe Position
toPosition string = case string of
first : second : rest ->
if isValidChar first
then if isValidInt second
then if null rest
then Just (Pos first (read second :: Int))
else Nothing -- more than two characters
else Nothing -- invalid second character
else Nothing -- invalid first character
isValidChar :: Char -> Bool
isValidChar x
|x == "A" || "B" || "C" || "D" || "E" || "F" || "G" || "H" = True
|otherwise = False
isValidInt :: Char -> Bool
isValidInt x
|x == 1 || 2 || 3 || 4 = True
|otherwise = False
It still gives me error:
Not in scope: type constructor or class ‘Pos’
So I'm wondering how can I represent my self-defined data type so that I don't get any more errors?
Since this is homework I won't provide a complete solution, but hopefully I can give enough to get you unstuck.
You can use pattern matching to get the first and second characters out of the string. Then you can use normal functions to determine if those characters are valid or not. Assuming that they are, you can build a Position value to return.
data Position = Pos Char Int
toPosition :: String -> Maybe Position
toPosition string = case string of
first : second : rest ->
if isValidChar first
then if isValidInt second
then if null rest
then Just (Pos first (charToInt second))
else Nothing -- more than two characters
else Nothing -- invalid second character
else Nothing -- invalid first character
anythingElse -> Nothing -- fewer than two characters
isValidChar :: Char -> Bool
isValidChar = undefined
isValidInt :: Char -> Bool
isValidInt = undefined
charToInt :: Char -> Int
charToInt = undefined

How can Haskell code utilise brackets to separate or tidy up information while using list comprehensions?

I am trying to write a function where the expression:
crosswordFind letter inPosition len words
should return all the items from words which
(i) are of the given length len and
(ii) have letter in the position inPosition.
For example, seven-letter words that have ’k’ in position 1, the expression:
crosswordFind ’k’ 1 7 ["funky", "fabulous", "kite", "icky", "ukelele"]
will return
["ukelele"]
Here is what I have so far:
crosswordFind :: Char -> Int -> Int -> [String] -> [String]
crosswordFind letter pos len words =
if isAlpha **words** == letter &&
**words** !! letter == pos &&
length **pos** == len
then words
else []
The code above is after altering to remove the brackets that I placed to separate each condition. The code below is the original one (which is wrong):
crosswordFind :: Char -> Int -> Int -> [String] -> [String]
crosswordFind letter pos len words =
[ if [isAlpha x == letter] &&
[xs !! n == pos] &&
[length x == len]
then words
else [] ]
I understand why it is wrong (because a list of length 1 will be returned), but why can't brackets like these be used to section off code in Haskell?
How can this question be solved using list comprehensions? And I'm wondering what to put in to replace the bolded words as well to make the code run normally.
You can filter with a condition that should satisfy two criteria:
the word has the given length; and
the character on position pos is the given letter.
For a word w of the words we thus check if length w == len and w !! pos == letter.
We thus can implement this with:
crosswordFind :: Eq a => a -> Int -> Int -> [[a]] -> [[a]]
crosswordFind letter pos len words = filter (\w -> length w == len && w !! pos == letter) words
we can also omit the words variable and work with:
crosswordFind :: Eq a => a -> Int -> Int -> [[a]] -> [[a]]
crosswordFind letter pos len = filter (\w -> length w == len && w !! pos == letter)
The above is not very safe: if the pos is greater than or equal to the length, then w !! pos == letter will raise an error. Furthermore for infinite strings (lists of Chars), length will loop forever. I leave it as an exercise to introduce safer variants. You can determine these with recursive functions.
Square brackets are part of list syntax. Nothing else.
Lists.
You can freely utilize round parentheses ( ) for the grouping of expressions.
Some expression types, like let and do, have their own separators {, ;, }, which can also be used, especially to prevent whitespace brittleness.

F# Remove/Replace char in a specific string index

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

Return a concatenated string in Haskell recursive function

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.

How to find the frequency of characters in a string in Haskell?

How can I count the frequency of characters in a string and then output them in sort of a table?
For example, if I input the word "happy" the result would be
h 1
a 1
p 2
y 1
If this could be ordered in ASCII order too that would be brilliant.
I know I need to use the count function, any other hints would be appreciated.
EDIT: All the answers are brilliant, only I'm such a beginner at Haskell that I don't actually understand what they are doing.
The simplest solution is to use a Data.Map to store the intermediate mapping from character to frequency. You can then construct the counts easily using fromListWith. Since Data.Map is sorted, you get them in ASCII order for free.
λ> :m + Data.Map
λ> let input = "happy"
λ> toList $ fromListWith (+) [(c, 1) | c <- input]
[('a',1),('h',1),('p',2),('y',1)]
So what's happening here?
The idea is to build a Data.Map (a tree map) using the characters as keys and the frequencies as values.
First, we take the input string and make tuples of each character with a 1 to indicate one occurrence.
λ> [(c, 1) | c <- input]
[('h',1),('a',1),('p',1),('p',1),('y',1)]
Next, we use fromListWith to build a sorted map from these key-value pairs by repeatedly inserting each key-value pair into a map. We also give it a function which will be used when a key was already in the map. In our case, we use (+) so that when a character is seen multiple times, we add the count to the existing sum.
Finally we covert the map back into a list of key-value tuples using toList.
There's probably something shorter, but this works:
Prelude> import Data.List
Prelude Data.List> map (\x -> (head x, length x)) $ group $ sort "happy"
[('h',1),('a',1),('p',2),('y',1)]
func xs = map (\a -> (head a, length a)) $ group $ sort xs
Use list comprehension, no need for any imports or sorting.
[ (x,c) | x<-['A'..'z'], let c = (length.filter (==x)) "happy", c>0 ]
Result:
[('a',1),('h',1),('p',2),('y',1)]
Above is the filtered and rewritten (only character with count > 0) from:
[(x,(length.filter (==x)) "happy" ) | x<-['A'..'z']]
Explanation:
Make a list of all characters that match a given character (A..z).
For each character, count this list (==length)
Put this count in a tuple with the character
I'll scetch a solution step by step. A shorter solution is possible using standard functions.
You want a sorted result, therefore
result = sort cs
where
cs would be a list of tuples, where the first element is the character and the second element is the number of times it appears.
cs = counts "happy"
counts [] = []
counts (c:cs) = (c, length otherc + 1) : counts nonc where
(otherc, nonc) = partition (c==) cs
That's all.
Interestingly, counts works on any list of items that support the == operator.
import Data.Array (Ix, accumArray, assocs)
eltDist :: (Bounded a, Ix a, Eq b, Num b) => [a] -> [(a, b)]
eltDist str = filter ((/=0) . snd ) $
assocs (accumArray (+) 0 (minBound, maxBound) [(i, 1) | i <- str])
"minBound" and "maxBound" are going to depend on the range of the type inferred for i. For Char it will be 0 - 1,114,111, which is extravagant but not impossible. It would be especially convenient if you were counting Unicode chars. If you are only interested in ASCII strings, then (0, 255) would do. A nice thing about arrays is that they can be indexed by any type that can be mapped to an integer. See Ix.
assocs pulls the indices and counts out of the array into a list of pairs and filter disposes of the unused ones.
//Count the frequency of character in a string
package waytocreateobject;
import java.util.Scanner;
public class Freqchara {
public static void main(String[] args) {
int c = 0, x = 0, loop = 26, space = 0;
int count[] = new int[loop];
//Arrays.fill(count, x);
Scanner sc = new Scanner(System.in);
String str =sc.nextLine();
char[] charr = str.toCharArray();
int aa = str.length();
//System.out.println(str.charAt(10));
//System.out.println(str.charAt(11));
for (int mm = 0; mm < aa; mm++) {
if (str.charAt(c) != '\0') { //Considering characters from 'a' to 'z' only and ignoring others.
if ((str.charAt(c) >= 'a') && (str.charAt(c) <= 'z')) {
x = (int) str.charAt(c) - (int) 'a';
// System.out.println(x);
count[x] = count[x] + 1;
}
c++;
} else {}
}
// printing all the charcter
int i = 97;
for (int j = 0; j < loop; j++) {
char ch = (char) (i + j);
System.out.println(ch + " occurs " + count[j] + " times in the string");
}
System.out.println(" occurs " + space);
}
}

Resources