3

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

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

任何帮助将不胜感激!

4

2 回答 2

4

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

不是通过查看字符串来确定要返回的类型read例如考虑:

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

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

您可能认为这与其他语言不同,例如 Python,您可以在其中 eval"[1,2,3]"并获取一个列表,而 eval"5"获取一个数字,而您不必告诉 eval 返回什么类型的东西。但是,Haskell 对此的回答是,这些语言实际上只处理一种类型,即 sum 类型,例如:

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

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

于 2016-06-19T05:55:58.830 回答
2

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

例如,假设我给你以下输入

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

你应该返回什么?如果我的意思是使用标准区分大小写的字符来解释,那么我应该返回False. 另一方面,如果我使用不区分大小写的字符(例如,此包提供的字符),那么我应该回来True。只是给我字符串表示是模棱两可的。

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

于 2016-06-19T17:28:51.327 回答