Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 存在构造函数的模式绑定_Haskell_Homoiconicity - Fatal编程技术网

Haskell 存在构造函数的模式绑定

Haskell 存在构造函数的模式绑定,haskell,homoiconicity,Haskell,Homoiconicity,在编写Haskell时,我曾接触过Lisp,但我注意到了一些奇怪的事情,但我没有理解 这很好: {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE ExistentialQuantification #-} data Foo = forall a. Show a => Foo { getFoo :: a } showfoo :: Foo -> String showfoo Foo{getFoo} = do show getFoo 鉴于此项

在编写Haskell时,我曾接触过Lisp,但我注意到了一些奇怪的事情,但我没有理解

这很好:

{-# 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
    
    我是否错过了什么,或者是因为haskell不是同性恋

    不。同象似性是一个危险的问题:每种语言都有其源文本和AST1,并且Haskell在内部实现为各种中间语言之间的一系列去修饰过程

    真正的问题是,
    中的…和的案例…具有根本不同的语义,这是有意的。与
    case…of
    的模式匹配是严格的,因为它强制对scrutinee进行评估,以便选择要评估的RH,但是
    let…in
    形式中的模式绑定是惰性的。从这个意义上讲,
    让e2中的p=e1
    实际上与~p->e2的案例e1最为相似(请注意使用
    ~
    !)的惰性模式匹配),这会产生类似但不同的错误消息:

    ghci> case undefined of { ~Foo{getFoo} -> show getFoo }
    
    <interactive>:5:22: error:
        • An existential or GADT data constructor cannot be used
            inside a lazy (~) pattern
        • In the pattern: Foo {getFoo}
          In the pattern: ~Foo {getFoo}
          In a case alternative: ~Foo {getFoo} -> show getFoo
    
    ghci>case未定义的{~Foo{getFoo}->show getFoo}
    :5:22:错误:
    •不能使用存在或GADT数据构造函数
    在惰性(~)模式中
    •在模式中:Foo{getFoo}
    在模式中:~Foo{getFoo}
    在另一种情况下:~Foo{getFoo}->show getFoo
    
    这在对的答复中有更详细的解释



    1如果您对此不满意,请注意,Haskell在大多数Lisper使用该词的意义上是同源的,因为它支持模拟Lisp的
    引号
    运算符,其形式为
    [|…|]
    引号括号,这些都是模板Haskell的一部分。

    我对此进行了一些思考,虽然起初这种行为似乎有些奇怪,但经过一些思考后,我想人们可以这样来证明:

    假设我以你的第二个(失败的)例子为例,经过一些按摩和价值置换后,我将其简化为:

    data Foo = forall a. Show a => Foo { getFoo :: a }
    
    main::IO()
    main = do
        let Foo x = Foo (5::Int)
        putStrLn $ show x
    
    这会产生错误:

    无法将预期类型“p”与实际类型“a”匹配,因为类型变量“a”将脱离其作用域

    如果允许模式匹配,x的类型是什么?好。。类型当然是
    Int
    。但是,
    Foo
    的定义指出,
    getFoo
    字段的类型是属于
    Show
    实例的任何类型。
    Int
    Show
    的一个实例,但它不是任何类型。。这是一个具体的问题。。在这方面,
    Foo
    中包含的实际特定类型的值将变为“可见”(即escape),因此违反了我们的明确保证,即
    对于所有a。显示a=>…

    如果我们现在查看通过在函数声明中使用模式匹配来工作的代码版本:

    data Foo = forall a . Show a => Foo { getFoo :: !a }
    
    unfoo :: Foo -> String
    unfoo Foo{..} = show getFoo
    
    main :: IO ()
    main = do
        putStrLn . unfoo $ Foo (5::Int)
    
    查看
    unfoo
    函数,我们发现没有任何东西表明
    Foo
    中的类型是任何特定类型。。(一个
    Int
    或其他)。。在该函数的范围内,我们所拥有的只是原始保证,即
    getFoo
    可以是
    Show
    的实例的任何类型。包装值的实际类型仍然是隐藏的和不可知的,因此没有违反任何类型的保证,幸福随之发生


    PS:我忘了提到,
    Int
    位当然是一个例子。。在您的情况下,
    foo
    值内的
    getFoo
    字段的类型是
    a
    类型,但这是GHC类型推断所指的特定(非存在)类型(而不是类型声明中的存在
    a
    )。。我刚刚提出了一个具体的
    Int
    类型的例子,以便更容易理解和更直观。

    这个问题是关于Haskell的,而不是Lisp。破坏者:“同音异象”实际上没有任何意义。你对同音异象的定义没有解决我的问题。。mk,更紧迫的是:可能是我在这里的理解有限:如果我将模式绑定设置为严格的,为什么它不编译?@zabeltech可能是因为它只是一个非常不常见的用例而没有实现。您当然可以在请求实现时提交一个问题。@zabeltech在任何情况下都是“同象似性”,即使它实现了,它也可以。即使在Lisp中,您也不希望涉及
    let
    的错误以
    大小写
    的形式报告。两种语言特征具有相似但不同的语义并保持分离,而不是将一种语言特征分解为另一种语言特征,这是一种与同源性完全正交的选择,GHC中的许多特征都是通过分解来定义的(例如
    do
    符号和
    LambdaCase
    )。嗯,是的,可能是没人打扰……我还是哈斯克尔的忠实粉丝。但是评估策略似乎会影响类型检查器,尽管您已经证明它确实会影响。。。你认为这有一个共同的感官原因吗?@zabeltech评估策略必须这样做