如何从Haskell中的任意类型[a]的stdin读取列表?

时间:2016-06-19 04:12:08

标签: haskell types io functional-programming io-monad

我正在编写一个函数,它接受任意列表并比较它们以查看是否是另一个列表。对于stdin,我想问用户两个列表,但我无法想出一种接受任意类型的方法。到目前为止,这是我的代码:

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

我的主要问题是第5行,我必须为read选择一种类型。

我想要的一些输入和输出示例,而我目前只能支持一个:

>>> [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

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:4)

read必须事先知道它正在阅读什么样的东西 - 这就是它的工作方式。

read查看字符串以确定要返回的类型的情况。例如,考虑:

read "1" :: Float
read "1" :: Int

第一次读取将返回Float(1.0),第二次读取将返回Int(1),即使正在读取的字符串完全相同。

您可能认为这与其他语言不同,例如Python,您可以在其中评估"[1,2,3]"并获取列表并使用eval "5"来获取数字,而不必告诉eval什么样的回报。但是,Haskell对此的回答是那些语言实际上只处理 one 类型,它是一种总和类型:

data PyVal  = PyNum Int
            | PyStr String 
            | PyList [ PyVal ]
            | PyDict [ (PyStr, PyVal) ]
            | ...

因此,可能的表达式的世界是封闭的。所以,实际上,eval知道它正在阅读什么样的东西。在Haskell中,您始终可以添加新类型,从而添加新的阅读器和显示功能。

答案 1 :(得分:2)

您的基本问题是与Haskell无关。简单地给某人两个字符串表示值不足以确定相等性。你必须告诉那个人这些值的解释应该是什么,因为一个字符串可以用很多方式解释。

例如,让我们说我给你以下输入

>>> ['a', 'b']
    ['A', 'B']

你应该回报什么?如果我的意思是使用标准区分大小写的字符来解释,那么我应该回到False。另一方面,如果我使用不区分大小写的字符(例如由this package提供),那么我应该回到True。只是给我字符串表示是不明确的。

如果您关心的是字符串表示本身,那么只需将read您的值放入字符串列表中,然后对其使用sublist。如果您确实关心该字符串的解释,那么您必须允许用户指定该解释,或者以某种方式在代码中指定该解释(其中@ErikR&amp; ADT编码和您的类型注释是两种可能性)