Reputation: 908
I'm writing a function that takes arbitrary lists and compares them to see if one is a sublist of the other. For stdin, I wanted to ask the user for two lists but I can't figure out a way to accept an arbitrary type. Here is my code so far:
1 main :: IO ()
2 main = do
3 l1 <- getLine
4 l2 <- getLine
5 print $ sublist (read l1 :: [Int]) (read l2:: [Int])
6
7 sublist :: Eq a => [a] -> [a] -> Bool
8 sublist b p = any ((b ==) . take len) . takeWhile ((len<=) . length) $ iterate tail p
9 where len = length b
My main issue is line 5
where I have to pick a type for read
.
Some examples of input and output I would want to have while I can only currently support one at a time:
>>> [1,2,3]
[1,2,3,4,5]
True
>>> ["a", "bc"]
["xy", "b", "bc"]
False
>>> [True, False, True]
>>> [False, True, False, True]
True
-- And even nested types
>>> [[1], [2,3]]
[[2,4], [1], [2,3], [4]
True
Any help would be greatly appreciated!
Upvotes: 3
Views: 310
Reputation: 3739
Your fundamental problem is Haskell-independent. Simply giving someone two string representations of values is not enough to determine equality. You have to tell that person what the interpretation of those values is supposed to be since one string can be interpreted many ways.
For example, let's say I give you the following inputs
>>> ['a', 'b']
['A', 'B']
What should you return? If I mean this to be interpreted using standard case-sensitive characters, then I should get back False
. If on the other hand I'm using case-insensitive characters (e.g. as provided by this package) then I should get back True
. Just giving me the string representations is ambiguous.
If what you care about is the string representation itself, then just read
your values into lists of strings and use sublist
on those. If you do care about the interpretation of that string, then you have to either allow the user to specify that interpretation, or specify that interpretation in code somehow (of which @ErikR's ADT encoding and your type annotations are two possibilities).
Upvotes: 2
Reputation: 52057
read
has to know in advance what kind of thing it is reading - that's just the way it works.
It is not the case that read
looks at the string to determine what type to return. For instance consider:
read "1" :: Float
read "1" :: Int
The first read will return a Float (1.0) and the second an Int (1) even though the string being read is exactly the same.
You might think this is different from other languages, such as Python, where you can eval "[1,2,3]"
and get a list and eval "5"
to get a number and you don't have to tell eval what kind of thing to return. However, Haskell's answer to that is those languages are really only dealing with one type which is a sum type like:
data PyVal = PyNum Int
| PyStr String
| PyList [ PyVal ]
| PyDict [ (PyStr, PyVal) ]
| ...
Hence the universe of possible expressions is closed. So, actually, eval knows what kind of thing it is reading. In Haskell you can always add new types and therefore new reader and show functions.
Upvotes: 4