为什么镜头包括 fromEnum/toEnum 的 Iso,而不是 show/read 的 Iso?

Why does lens include an Iso for fromEnum/toEnum, but not one for show/read?

假设你声明了两个同构

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

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

它们是不安全的,并非每个字符串都会解析为 a。

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

它同样不安全,类型系统无法阻止。他们都将负担转移到必须确保转换不会破坏同构的程序员身上。

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

警告:推测性答案如下。

我能想到的两种情况之间的一个区别是,在 toEnum 发生故障时很容易弄清楚(引用 the lens docs: "this is only an isomorphism from the numeric range actually used"), while things are a fair bit murkier when it comes to read. Another difference is that toEnum is a method of Enum (and one required in a minimal instance definition, at that), while read isn't actually a method of Read, and so is, in a sense, less essential (in fact, the base docs explicitly discourage its usage)。

更笼统地说,在公开防弹接口和包含有用但可能不安全或非法的组合器之间进行选择时,lens 通常选择后者,让那些希望使用它们的人可以使用它们,同时承认文档中的任何潜在问题(或者,在更棘手的情况下,函数和模块名称中)。鉴于 lens 是一个非常通用的库,这种方法可以被视为一种不拘一格的选择——在这样的情况下,很难弥补组合器的缺失.

P.S.: 同样值得注意的是,lens通过the _Show prism编码了readshow_Show 等同于 prism' show readMaybe,并且对于 Read-ing 值的偏向性是安全的。

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

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