Обновление записи с использованием RecordDotSyntax приводит к ошибке

avatar
dharmatech
9 августа 2021 в 05:25
306
2
2

Контекст

Если я загружу следующее в ghc-9.2.1-alpha2, который поддерживает RecordDotSyntax:

{-# 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-08-10

Если я добавлю следующее как псевдоним и предложено Ари:

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.
Источник
alias
9 августа 2021 в 06:08
1

Явно import Prelude. При наличии перепривязываемого синтаксиса GHC не импортирует его неявно. См. здесь: downloads.haskell.org/ghc/latest/docs/html/users_guide/exts/…

dharmatech
9 августа 2021 в 07:56
0

@alias Похоже, это сблизило меня! Теперь ошибок меньше. После добавления import Prelude я получаю: Not in scope: ‘getField’. Думаю, мне нужен еще один явный импорт?

Noughtmare
9 августа 2021 в 09:51
1

getField происходит от GHC.Records.

dharmatech
10 августа 2021 в 22:06
0

@alias Гоша, я мог бы поклясться, что проверил ваше предложение выше и, таким образом, принял ответ. Однако теперь, когда я пытаюсь сделать это снова после добавления import GHC.Records, я на самом деле вижу это: Not in scope: ‘setField’, за которым следует Perhaps you meant ‘getField’ (imported from GHC.Records).

Ответы (2)

avatar
Ari Fordsham
11 августа 2021 в 11:47
2

Здесь две проблемы.

  1. Вы включили RebindableSyntax. Это позволяет вам переопределить определенное поведение путем определения определенных функций, импортированных из Prelude, в локальной области. Следовательно, RebindableSyntax подразумевает NoImplicitPrelude. Вам необходимо вручную импортировать Prelude, при желании скрыв функции, которые вы хотите переопределить.

    import Prelude hiding (...)
    
  2. Вы включили OverloadedRecordUpdate, экспериментальную функцию из GHC 9.2, которая еще не была стабилизирована.

    В соответствующей версии Руководства пользователя GHC говорится следующее:

    В настоящее время RebindableSyntax должен быть включен при OverloadedRecordUpdate, и пользователи должны предоставить определения для getField и setField. Мы ожидаем, что это ограничение будет снято в будущем выпуске GHC со встроенной поддержкой setField.

    .

    Значение по умолчанию getField можно импортировать из GHC.Records, но setField в настоящее время недоступно, поэтому его необходимо реализовать самостоятельно.

    Повеселитесь!

dharmatech
11 августа 2021 в 13:42
0

Ах, хорошо, это имеет смысл. Сюжет закручивается! :-) Спасибо, Ари. Будет здорово, когда выйдет GHC 9.2.1.

Ari Fordsham
11 августа 2021 в 14:25
0

Отличный, но, наверное, другой :-). Само собой разумеется, я надеюсь, что вы не используете этот код в производстве :-)

dharmatech
11 августа 2021 в 16:01
0

Определенно не использовать это в коде в производстве прямо сейчас. :-) Это вышло этот (противоречивый) эксперимент я разместил в сабреддите Haskell.

avatar
Ari Fordsham
9 августа 2021 в 17:06
1

РЕДАКТИРОВАТЬ 11/08: Этот ответ в основном неполный и частично неверный. Смотрите мой другой ответ.

Как объяснил @alias, если вы включите RebindableSyntax, Prelude не будет загружаться автоматически. Не будет и GHC.Records, обычно загружаемого и требуемого расширениями синтаксиса записи.

Вы должны добавить это:

import Prelude
import GHC.GetRecords
dharmatech
10 августа 2021 в 22:08
0

Боже, я мог бы поклясться, что проверил ваше предложение выше и, таким образом, принял ответ. Однако теперь, когда я пытаюсь снова добавить import GHC.Records, я на самом деле вижу это: Not in scope: ‘setField’, за которым следует Perhaps you meant ‘getField’ (imported from GHC.Records).