testing for same characters in lists of strings

I'm new to Haskell, and I'm finding it is very different from any other language I have worked with. I have an assignment to make a program to test whether two lists use the same characters for each string. e.g. sameCharacter ["rock", "cab"] ["cork", "abc"] True My plan to tackle this was to use: nub to eliminate duplications, sort to put the characters in order, and map to put characters together.. and then somehow check to see if these characters are the same. My problem right now is just figuring out how to make a function that uses these three functions to give me a list of tuples. I know this is an awfully newbish question, and I'm not trying to get an answer to my homework problem. I just need some sort of working example syntax to off of. Any help would be appreciated! Thanks. -- View this message in context: http://www.nabble.com/testing-for-same-characters-in-lists-of-strings-tp1654... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On Mon, Apr 07, 2008 at 07:51:05PM -0700, Jackm139 wrote:
I have an assignment to make a program to test whether two lists use the same characters for each string. e.g.
sameCharacter ["rock", "cab"] ["cork", "abc"] True
My plan to tackle this was to use: nub to eliminate duplications, sort to put the characters in order, and map to put characters together.. and then somehow check to see if these characters are the same.
Probably you won't need to eliminate duplicates, sorting would be enough (although it depends on the assignment details). Comparing Chars (and Strings) can be accomplished with
(==) :: (Eq a) => a -> a -> Bool
My problem right now is just figuring out how to make a function that uses these three functions to give me a list of tuples.
To get list of tuples you can use
zip :: [a] -> [b] -> [(a, b)]
or alternatively you can apply a binary function in a "pairwise way" using
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
as in
zipWith (+) [1, 2] [3, 4] [4, 6]
For chaining functions you can use function composition:
(.) :: (b -> c) -> (a -> b) -> a -> c
as in
not :: Bool -> Bool and :: [Bool] -> Bool nand :: [Bool] -> Bool nand = not . and
or do without composition by specifying all arguments:
nand xs = not (and xs)
Hope this helps, -- Krzysztof Kościuszkiewicz Skype: dr.vee, Gadu: 111851, Jabber: kokr@jabberpl.org "Simplicity is the ultimate sophistication" -- Leonardo da Vinci

On Tue, Apr 8, 2008 at 1:51 PM, Jackm139
I have an assignment to make a program to test whether two lists use the same characters for each string. e.g.
sameCharacter ["rock", "cab"] ["cork", "abc"] True
I would start with something smaller: try defining a function that will check if two *strings* use the same characters. It would look something like this: same :: String -> String -> Bool same xs ys = normalize xs == normalize ys normalize :: String -> String normalize xs = error "insert your implementation here" Define the "normalize" function so that it does whatever is necessary to make two strings with the same characters into the same string (using nub, sort, and/or whatever else is appropriate). Once you have the "same" function working, you can use it to define "sameCharacter". You might want to take a look at the functions "zip", "zipWith", "all", and "and", which can be found in the Prelude. Hopefully this will help you get started. Stuart

I don't know how to calibrate my response to what you are really asking for. Depending on how "new" you are, maybe all you want is just "working syntax" to get you started. Here is a structurally similar problem, if it helps. (And if you are more advanced, try the extra credit!) Find the "average" of a string, i.e. the Char with the average ascii value of the string: e.g. (avgChar "ac") == 'b' and (avgChar "ffff") == 'f'. Things to watch out for: 1) What if the string is empty? [I will error out] 2) What if the average is not an integer? [Just use div to truncate] You should also provide guarantees to the caller in your documentation, if you can (and ideally, automated checks for them): 3) If the string is nonempty and contains only lowercase letters, is the average always a lowercase letter? 4) If I permute the string (e.g. sort it), does it give the same average? [Extra credit: can you prove 3 and 4 are true or false?] Here is one solution to the above problem. Save the code below to a file Avg.hs, then compile: ghc --make Avg When you run Avg, you should get 'j', the average of "hello". ------------------------------------------------------------------- main = putStrLn . show $ avg "hello" -- Should print 'j' -- How to convert a Char to its ascii value: charToAscii :: Char -> Int charToAscii c = fromEnum c -- Convert each element of the string: stringToAsciiList :: String -> [Int] stringToAsciiList s = map charToAscii s -- Get the average of a list of ints: avgIntListValue :: [Int] -> Int avgIntListValue [] = error "Dummy! I can't handle an empty list" avgIntListValue xs = sum xs `div` length xs -- Now convert the ascii back to a Char: asciiToChar :: Int -> Char asciiToChar i = toEnum i -- Now put it all together. Remember that the composition operator (.) -- works backwards: given two functions f :: a -> b and g :: b -> c, -- then g . f :: a -> c avgChar :: String -> Char avgChar s = (asciiToChar . avgIntListValue . stringToAsciiList) s -- NOTE: I could have left the argument off and defined the functions -- in a "point-free" style. For example, you can also write: avgChar' = asciiToChar . avgIntListValue . stringToAsciiList ------------------------------------------------------------------- Others have provided suggestions more specific to your particular assignment. Dan Jackm139 wrote:
I'm new to Haskell, and I'm finding it is very different from any other language I have worked with.
I have an assignment to make a program to test whether two lists use the same characters for each string. e.g.
sameCharacter ["rock", "cab"] ["cork", "abc"] True
My plan to tackle this was to use: nub to eliminate duplications, sort to put the characters in order, and map to put characters together.. and then somehow check to see if these characters are the same.
My problem right now is just figuring out how to make a function that uses these three functions to give me a list of tuples.
I know this is an awfully newbish question, and I'm not trying to get an answer to my homework problem. I just need some sort of working example syntax to off of.
Any help would be appreciated! Thanks.

On Mon, 7 Apr 2008, Jackm139 wrote:
I'm new to Haskell, and I'm finding it is very different from any other language I have worked with.
I have an assignment to make a program to test whether two lists use the same characters for each string. e.g.
sameCharacter ["rock", "cab"] ["cork", "abc"] True
My plan to tackle this was to use: nub to eliminate duplications, sort to put the characters in order, and map to put characters together.. and then somehow check to see if these characters are the same.
How about converting the strings to Set Char and comparing the resulting lists?

Thanks for all the replies! I have it working somewhat. It works as long as there is only one string in each list, but if the lists contain more than one string it fails. here is what I have: import List same :: [[Char]] -> [[Char]] -> Bool same [xs] [ys] = map (normalize) [[xs]] == map (normalize) [[ys]] normalize :: [String] -> [String] normalize [xs] = [(sort (nub xs))] How can I make this work for lists that contain more than one string? -- View this message in context: http://www.nabble.com/testing-for-same-characters-in-lists-of-strings-tp1654... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On Tue, Apr 8, 2008 at 10:24 AM, Jackm139
import List
same :: [[Char]] -> [[Char]] -> Bool same [xs] [ys] = map (normalize) [[xs]] == map (normalize) [[ys]]
normalize :: [String] -> [String] normalize [xs] = [(sort (nub xs))]
Your pattern binding [xs] and [ys] says to only match when the list contains one element. Otherwise, you get a pattern-matching failure at run-time. Use "normalize xs" to match a list of strings, and "same xs ys" to match lists of lists. xs and ys will have different types with those patterns, but you'll get it. Justin

On Tue, 8 Apr 2008, Jackm139 wrote:
Thanks for all the replies! I have it working somewhat. It works as long as there is only one string in each list, but if the lists contain more than one string it fails. here is what I have:
import List
same :: [[Char]] -> [[Char]] -> Bool same [xs] [ys] = map (normalize) [[xs]] == map (normalize) [[ys]]
normalize :: [String] -> [String] normalize [xs] = [(sort (nub xs))]
'normalize' (if correctly implemented) is essentially the same as 'Data.Set.fromList'
participants (6)
-
Dan Weston
-
Henning Thielemann
-
Jackm139
-
Justin Bailey
-
Krzysztof Kościuszkiewicz
-
Stuart Cook