为什么镜头包含一个用于fromEnum / toEnum的Iso,而不是一个用于显示/读取的?

时间:2018-06-03 23:31:49

标签: haskell lens

假设您声明了两个同构

showing :: (Read a, Show a) => Iso' String a
showing = iso read show

reading :: (Read a, Show a) => Iso' a String
reading = iso show read

它们不安全,并非每个String都会解析为a。

这引出了一个问题:如果enum = iso fromEnum toEnum是,那么为什么这两个人不会被包含在库中?

它同样不安全,不能被类型系统阻止。他们都把负担转嫁给程序员,程序员必须确保转换不会破坏同构。

快速示例:under enum (+1) True将抛出异常

2 个答案:

答案 0 :(得分:6)

警告:随后是推测性答案。

我能想到的两个场景之间的一个区别是,当toEnum出现故障时,可以相当容易地澄清(引用the lens docs:"这只是来自数值范围的同构实际使用"),而read涉及的事情有点模糊。另一个区别是toEnumEnum的方法(在最小实例定义中需要一个方法),而read实际上不是{{1}的方法在某种意义上,从某种意义上讲,它不那么重要(事实上, base docs explicitly discourage its usage)。

更一般地说,当涉及在暴露防弹界面和包括有用但可能不安全或非法的组合器之间进行选择时,镜头通常适用于后者,使它们适用于那些谁愿意使用它们同时承认文档中的任何潜在问题(或者,在更多的情况下,在函数和模块名称中)。鉴于镜头是一个非常通用的库,这种方法可以被视为一种非自以为是的选择 - 在这样的上下文中,很难弥补组合器的缺失。

P.S。:值得注意的是,镜头Readreadthe _Show prism进行编码。 show相当于_Show,并且对于prism' show readMaybe值的偏倚是安全的。

答案 1 :(得分:1)

除了其他答案中的优秀评论外,我对这些定义的合法性犹豫不决。对于定义的标准实例,fromEnum . toEnum(反之亦然)实际上是id。但show . read不是,即使对于完全定义的值并且仅使用标准实例,因为它规范化格式化和括号:

> show (read "(5)" :: Int)
"5"
Data.Tree> show (read "Node     {      rootLabel=3 ,subForest=[]}" :: Tree Int)
"Node {rootLabel = 3, subForest = []}"