作为一个接触过 Lisp 的程序员,在编写 Haskell 时,我注意到了一些奇怪的东西,我没能理解。
这编译得很好:
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Show a => Foo { getFoo :: a }
showfoo :: Foo -> String
showfoo Foo{getFoo} = do
show getFoo
而这失败了:
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Show a => Foo { getFoo :: a }
showfoo :: Foo -> String
showfoo foo = do
let Foo{getFoo} = foo
show getFoo
对我来说,第二个片段失败的原因并不明显。
问题是:
我是否错过了某些东西或由于 haskell 不是同音异形这一事实而导致了这种行为?
我的理由是,鉴于:
Haskell 需要将记录模式匹配实现为编译器扩展,因为它选择使用语法而不是数据。
函数头或 let 子句中的匹配是两种特殊情况。
很难理解这些特殊情况,因为它们既不能实现,也不能直接在语言本身中查找。
因此,无法保证整个语言的一致行为。尤其是与其他编译器扩展一起,例如。
ps:编译错误:
error:
• My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.
• In the pattern: Foo {getFoo}
In a pattern binding: Foo {getFoo} = foo
In the expression:
do { let Foo {getFoo} = foo;
show getFoo }
编辑:不同的编译器版本会针对相同的问题给出此错误
* Couldn't match expected type `p' with actual type `a'
because type variable `a' would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor: Foo :: forall a. Show a => a -> Foo