为什么IsList需要toList?
使用时-XOverloadedStrings你可以实现IsString只需要一个函数fromString。现在,如果您想使用字符串文字进行模式匹配,您还必须实现Eq,这是有道理的:
f :: MyString -> Bool
f "foo" = True
f _ = False
-- equivalent to
f x
| x == fromString "foo" = True
| otherwise = False
但是,为什么使用的IsList类型类-XOverloadedLists需要您实现toList?在wiki 中,唯一提到的用例toList是模式匹配。我知道这Eq对于列表模式匹配是不够的。但后来toList应该是在唯一需要不同类型的类,如果你想使用列表模式匹配与你的类型,就像IsString没有要求 Eq。
对我来说,令人讨厌的事情是fromList . toList = id必须满足条件,但是对于某些类型(例如无序集合,它不能保证元素的顺序保持不变),这根本无法保证。
这似乎非常不一致。
回答
两个扩展中的重载只是一个符号。两种表示法之间的区别在于,列表可以包含变量 ( [x, y]) 而字符串不能:Haskell 不会像这样进行变量插值let x = "apple" in "I like {x} pie")
当我在模式中使用任一符号时,这种差异变得很重要:我希望能够在模式中绑定变量,例如
f :: MyList Int -> Bool
f [x, y] = x > y
...虽然我可以使用字符串文字作为模式
f :: MyString -> Bool
f "apple" = True
...那些永远不会绑定变量
要查看这产生的差异,假设-XOverloadedLists将完全像-XOverloadedStrings. 模式匹配
f [x,y] = x > y
将被翻译为
f z
| z == fromList [x, y] = x > y
但fromList [x, y] 不是构造函数模式:对于给定的z,可能有几个不同的 值,x并且y这样fromList [x, y] == z(在您的示例中,无序集合{1, 2}等于fromList [1, 2]但也为fromList [2, 1]- 那么结果应该f {1, 2}是True还是False?
这表明要使模式匹配起作用,Mylist a需要同构到[a],换句话说,toList需要满足适当的定律。然后我们可以找到唯一的 x, y使得z == fromList [x, y]通过应用toList到z,所以翻译是
f z
| toList z == [x, y] = x > y
或者,使用视图模式(甚至Eq不再需要):
f (toList -> [x,y]) = x > y
因此,最终,IsList没有 的类toList将不允许重载列表模式,但仍然可以{1, 2}使用列表符号表示无序集合[1, 2]。但是,我们必须-XOverloadedLists和-XOverloadedListPatterns-可能不值得冒这个险。