【问题标题】:Updating a record using RecordDotSyntax results in an error使用 RecordDotSyntax 更新记录会导致错误
【发布时间】:2021-08-09 05:25:18
【问题描述】:

上下文

如果我将以下内容加载到支持RecordDotSyntaxghc-9.2.1-alpha2 中:

{-# LANGUAGE OverloadedRecordDot, OverloadedRecordUpdate, DuplicateRecordFields #-}
----------------------------------------------------------------------
data Point = Point { x :: Double, y :: Double }

instance Show Point where
    show p = "Point { x = " ++ show p.x ++ ", y = " ++ show p.y ++ " }"

p = Point 10 20

然后我可以在 ghci 中运行以下命令:

ghci> p { x = 30 }
Point { x = 30.0, y = 20.0 }

酷,它正在工作!

问题

但是,如果我在上面的测试文件中添加以下内容:

result =
    let
        a = Point 1 2
        b = a { x = 3 }
    in
        b

然后重新加载,我收到以下消息:

ghci> :r
[1 of 1] Compiling Main             ( /home/dharmatech/tmp/test-ghc-9.2.0.20210422/point-update-issue.hs, interpreted )

/home/dharmatech/tmp/test-ghc-9.2.0.20210422/point-update-issue.hs:13:13: error:
    RebindableSyntax is required if OverloadedRecordUpdate is enabled.
   |
13 |         b = a { x = 3 }
   |             ^^^^^^^^^^^
Failed, no modules loaded.

我尝试过的

如果我按照消息提示添加RebindableSyntax,则会收到更多错误,如下所示:

/home/dharmatech/tmp/test-ghc-9.2.0.20210422/point-update-issue.hs:3:27: error:
    Not in scope: type constructor or class ‘Double’
  |
3 | data Point = Point { x :: Double, y :: Double }
  |

问题

有没有办法让它工作?还是只是还没有实现?

2021 年 8 月 10 日更新

如果我将以下内容添加为 aliasAri 建议:

import Prelude
import GHC.Records

我得到以下信息:

point-update-issue.hs:17:13: error:
    Not in scope: ‘setField’
    Perhaps you meant ‘getField’ (imported from GHC.Records)
   |
17 |         b = a { x = 3 }
   |             ^^^^^^^^^^^
Failed, no modules loaded.

【问题讨论】:

  • 明确import Prelude。在存在可重新绑定语法的情况下,GHC 不会隐式导入它。见这里:downloads.haskell.org/ghc/latest/docs/html/users_guide/exts/…
  • @alias 看起来这让我更接近了!现在错误少了。添加import Prelude 后,我得到:Not in scope: ‘getField’。我想我需要另一个显式导入?
  • getField 来自GHC.Records
  • @alias Gosh,我可以发誓我在上面测试了你的建议,因此接受了答案。但是,现在我在添加 import GHC.Records 后再次尝试,我实际上看到了这个:Not in scope: ‘setField’ 后跟 Perhaps you meant ‘getField’ (imported from GHC.Records)

标签: haskell ghc


【解决方案1】:

这里有两个问题。

  1. 您已启用RebindableSyntax。这允许您重新定义某些行为 通过在本地范围内定义某些函数,否则从 Prelude 导入。因此,RebindableSyntax 意味着 NoImplicitPrelude。您需要手动导入Prelude,可选择隐藏您想要覆盖的函数。

    import Prelude hiding (...)
    
  2. 您已启用OverloadedRecordUpdate,这是 GHC 9.2 中尚未稳定的实验性功能。

    GHC User's Guide的相关版本是这样说的:

    此时必须在 OverloadedRecordUpdate 时启用 RebindableSyntax,并要求用户提供 getField 和 setField 的定义。我们预计此限制将在 GHC 的未来版本中取消,并内置对 setField 的支持。

    默认的getField可以从GHC.Records导入,但setField目前不可用,需要自己实现。

    玩得开心!

【讨论】:

  • 啊,好吧,这是有道理的。剧情变厚了! :-) 谢谢阿里。当 GHC 9.2.1 发布时会很棒。
  • 很好,但也可能不同:-)。不用说,我希望你没有在生产中使用这段代码:-)
  • 现在绝对不会在生产代码中使用它。 :-) 这出来了 this (controversial) experiment 我发布到 Haskell subreddit。
【解决方案2】:

编辑 11/08:这个答案大多不完整,部分不正确。请参阅我的其他答案。

正如@alias 所解释的,如果启用RebindableSyntax,Prelude 将不会自动加载。 GHC.Records 也不会,通常由记录语法扩展加载和要求。

你必须添加这个:

import Prelude
import GHC.GetRecords

【讨论】:

  • 天哪,我可以发誓我在上面测试了你的建议,因此接受了答案。但是,现在我在添加import GHC.Records 后再次尝试,我实际上看到了这个:Not in scope: ‘setField’ 后跟Perhaps you meant ‘getField’ (imported from GHC.Records)
猜你喜欢
  • 2012-11-22
  • 2018-04-11
  • 2014-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-23
  • 1970-01-01
  • 2022-06-13
相关资源
最近更新 更多