3

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!

9
  • 2
    Give a couple of examples of what the user might enter as input and what type you want to interpret that input as. Commented Jun 19, 2016 at 4:45
  • good idea, I added them in Commented Jun 19, 2016 at 4:57
  • Can the user enter: [ 1, 2, "cat" ]? Commented Jun 19, 2016 at 5:03
  • yes but, that's not a valid Haskell list so the type system would reject it. (even if I had a polymorphic input function) Commented Jun 19, 2016 at 5:06
  • 1
    The exercise was to write sublist but now that I've done it I want to figure out a way for a polymorphic input without having to change line 5 every time I want a different type of input. I don't know of a way to turn the inputs into lists. Commented Jun 19, 2016 at 5:22

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.