【发布时间】:2012-04-27 11:26:37
【问题描述】:
(以下,将Show和Read简化为
class Show a where show :: a -> String
class Read a where read :: String -> a
并假设read 永远不会失败。)
众所周知,可以制作一种存在类型的表单
data ShowVal where
ShowVal :: forall a. Show a => a -> ShowVal
然后构造一个“异构列表”:: [ShowVal],比如
l = [ShowVal 4, ShowVal 'Q', ShowVal True]
众所周知,这是相对没用的,因为相反,可以
只需构造一个列表:: [String],如
l = [show 4, show 'Q', show True]
这完全是同构的(毕竟,唯一可以用
ShowVal 是 show 它)。
懒惰使这特别好,因为对于列表中的每个值,
show 的结果是自动记忆的,所以没有String 被计算超过
一次(并且根本不计算未使用的Strings)。
ShowVal 等价于存在元组exists a. (a -> String, a),
其中函数是Show 字典。
可以为Read 进行类似的构造:
data ReadVal where
ReadVal :: (forall a. Read a => a) -> ReadVal
注意,因为read 的返回值是多态的,所以ReadVal 是
普遍的而不是存在的(这意味着我们在
全部,因为 Haskell 具有一流的通用性;但我们将在这里使用它
突出显示与Show 的相似之处。
我们也可以列个名单:: [ReadVal]:
l = [ReadVal (read "4"), ReadVal (read "'Q'"), ReadVal (read "True")]
就像Show 一样,列表:: [ReadVal] 同构于列表:: [String],
比如
l = ["4", "'Q'", "True"]
(我们总能找回原来的String
newtype Foo = Foo String
instance Read Foo where read = Foo
因为Read 类型类是开放的。)
一个ReadVal 等价于一个通用函数forall a. (String -> a) -> a
(CPS 风格的表示)。这里Read 字典由用户提供
ReadVal 的而不是生产者的,因为返回值是
多态而不是参数。
但是,在这两种表示中,我们都没有得到自动
我们用Show 在String 表示中得到的记忆。让我们这么说
read 因为我们的类型是一个昂贵的操作,所以我们不想计算它
同一类型的同一String 上不止一次。
如果我们有一个封闭的类型,我们可以这样做:
data ReadVal = ReadVal { asInt :: Int, asChar :: Char, asBool :: Bool }
然后使用一个值
ReadVal { asInt = read s, asChar = read s, asBool = read s }
或者类似的东西。
但是在这种情况下——即使我们只使用ReadVal 作为一种类型——
String 将在每次使用该值时进行解析。有没有简单的方法
在保持ReadVal 多态的同时获得记忆?
(让 GHC 自动执行此操作,类似于 Show 的情况,将是
理想,如果有可能的话。更明确的记忆方法——
也许通过添加Typeable 约束? -- 也可以。)
【问题讨论】:
-
您的
ReadVal代码毫无意义。你写ReadVal "4"好像它与整数4有关。为什么不讨论ReadVal 4呢?一旦你意识到ReadVal 4是可能的,很明显[ReadVal]根本不与[String]同构。 -
你说得对——我的意思是
ReadVal (read "4")。我应该在发布之前进行类型检查...我会更新问题以反映这一点,谢谢。 (不过,ReadVal 4也是无效的,因为ReadVal的参数需要比Num更具多态性。) -
我想到了一个像
data ReadVal = forall a. Read a => ReadVal a这样的定义,没有 GADT。有了这个定义ReadVal 4是可能的。我更仔细地查看了您的定义,我承认我根本不理解它。 -
我的定义等同于
data ReadVal = ReadVal (forall a. Read a => a)——即,普遍的,而不是存在的。它根本不需要包装器;我只是把它放在那里以显示与ShowVal的相似性。 -
像您描述的那样存在主义的
ReadVal不会很有用——您将无能为力。它就像一个元组exists a. (String -> a, a)。
标签: haskell polymorphism lazy-evaluation memoization