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