haw*_*eye 14 polymorphism haskell types clojure clojure-core.typed
最后,给定足够的宏魔法可以做到这一点......但现在可能比在Clojure上实现Haskell风格类型系统更省力.类型化的Clojure可能是一个很好的模型,除了它已被明确设计,以便Clojure的语义不受推断类型的影响.这正是返回类型多态中发生的事情,因此在Typed Clojure中显然是不可能的.
我的问题是 - 什么意思(Haskell的)语义受推断类型(返回类型多态)的影响?
Car*_*arl 22
考虑read函数,它具有(ad-hoc)多态返回值:
read :: (Read a) => String -> a
Run Code Online (Sandbox Code Playgroud)
实施并不那么重要.唯一重要的部分是实现依赖于Read在编译时选择的实例,并且推断可能导致为同一调用选择不同的类型read.
addFive :: Int -> Int
addFive x = x + 5
main :: IO ()
main = do
print (addFive (read "11"))
putStrLn (read "11")
Run Code Online (Sandbox Code Playgroud)
read两次调用相同的参数.Haskell需要引用透明度,因此它必须同时产生相同的事情,对吧?嗯,不太好.推断的返回类型很重要.在该print行中,推断的返回类型是Int.在该putStrLn行中,推断的返回类型是String.因为它是ad-hoc多态的,语义随着类型变量而变化.
该print行将打印出16 putStrLn行.该行将崩溃,因为"11"它不是read将成功解码为a 的输入String.
并且因为类型变量仅出现在返回类型中,所以在调用函数时没有该类型的值.在运行时无法分配值的类型以确定Read要使用的实例.解决问题的唯一方法是在编译时知道类型.所以Typed Clojure不能这样做 - 它意味着语义依赖于编译时类型.
我不知道它是否应该给你留下深刻印象.但由于你的陈述(2)在各方面都是错误的,它表明即使理解这个例子也显然缺乏基础.我想我必须一直回到Haskell中类型变量的含义来解释这一点.
Haskell中的类型变量表示由调用者选择的未知但具体的类型.该类型Read a => String -> a并不意味着函数根据其输入为其返回值选择类型.这意味着函数根据输出的类型选择它的工作方式.
也许这read是一个糟糕的例子,因为它的不同行为只有在由于输入错误而抛出异常时才会显得特别不同.对于没有Haskell类型系统经验的人来说,很容易将其与运行时转换异常等内容混淆,即使它完全不同.
你的陈述(2)完全错了.程序不会崩溃,因为read返回Int代码期望的位置String,以及类似的ClassCastException情况.程序崩溃是因为在编译时根据其返回类型read 选择了解析器来解析String文字,但是给出的输入不是有效的String文字.(相反,它"\"11\""是一个有效的String文字,因为它被引用.)
粗体部分是重要的部分.该read函数根据返回类型选择在编译时使用的解析器.这既是一种非常强大的技术,也是使用Typed Clojure无法做到的.