Hint.interpret выдает ошибку компилятора при использовании значения Polysemy.Sem.

Я пытаюсь скомпилировать монадные значения Polysemy в время выполнения с использованием Hint (Language.Haskell.Interpreter< /а>).

Когда я пытаюсь это сделать, я надежно получаю сообщение об ошибке о неправильном использовании оператора : в «интерактивном» коде; кажется, что текстовая подсказка, передаваемая GHC, содержит синтаксическую ошибку.

{-# LANGUAGE DataKinds #-}

module Main where

import Polysemy (Embed, embed, runM, Sem)
import Language.Haskell.Interpreter (as, interpret, Interpreter, runInterpreter, setImportsQ)
import Data.Typeable (typeOf)
import Control.Monad.IO.Class (liftIO)

main :: IO ()
main = do
  -- Hint works fine to interpret a String:
  m <- interpretWithErrors exampleHint
  print m
  -- And Sem works fine:
  runM exampleSem
  -- But notice the weird detected type:
  print $ typeOf exampleSem
  -- And now Hint fails to interpret a Sem:
  s <- interpretWithErrors exampleBoth
  print $ typeOf s
  runM s

type MyEffect = Sem '[Embed IO] ()

exampleSem :: MyEffect
exampleSem = embed $ print "Successful Sem!"

exampleHint :: Interpreter String
exampleHint = do
  setImportsQ [("Prelude", Nothing)]
  interpret "\"Successful Hint!\"" (as :: String)

exampleBoth :: Interpreter MyEffect
exampleBoth = do
  setImportsQ [("Prelude", Nothing), ("Polysemy", Nothing)]
  liftIO $ print "Successfully imported!"
  -- This is where it fails:
  s <- interpret "embed $ print \"Success!\"" (as :: MyEffect)
  liftIO $ print "Successfully interpreted!"
  return s

interpretWithErrors :: Interpreter a -> IO a
interpretWithErrors i_a = do
  e_e_a <- runInterpreter i_a
  either (ioError . userError . show) (return) e_e_a

Запуск вышеуказанных отпечатков:

"Successful Hint!"
"Successful Sem!"
Sem (': ((* -> *) -> * -> *) (Embed IO) ('[] ((* -> *) -> * -> *))) ()
"Successfully imported!"
Hint-Polysemy: user error (WontCompile [GhcError {errMsg = "<interactive>:3:41: error: Operator applied to too few arguments: :"}])

Некоторые примечания:

  • Я использую cabal, и для того, чтобы передать строку import в монаде интерпретатора, я должен запустить это из изолированной оболочки Cabal, потому что Polysemy не установлен на моей машине в целом.
  • Тем не менее, я не думаю, что клика или импорт Полисемии являются проблемой. Я могу получить то же самое сообщение об ошибке, что и выше, если просто пренебрег импортом Polysemy и просто setImportsQ [("Prelude", Nothing)].
  • Строка, которую я интерпретирую, даже не обязательно должна быть допустимым выражением; Я могу вставить туда тарабарщину без изменения ошибки. Это наводит меня на мысль, что проблема с (as :: MyEffect).
  • Я включаю typeOf, чтобы продемонстрировать, что MyEffect на самом деле Typeable.
  • Я понятия не имею, почему typeOf exampleSem дает такую ​​длинную и странную подпись типа. Я думаю, что это как-то проблема. Перестановка MyEffect в type MyEffect = Sem ((Embed IO) : []) () не дает результата.

Кому-нибудь понятно, что я делаю что-то не так? Как мне попытаться отладить эту проблему?
Предположим, это ошибка в подсказке, полисемии или (что менее вероятно) в
Type.Reflection.Typeable, каким будет мой следующий шаг, чтобы попытаться это исправить? Я предполагаю, что мне как-то придется определить, в какой библиотеке возникла проблема?

Это уточнение предыдущего вопроса. Вот оригинал.


person ShapeOfMatter    schedule 27.12.2019    source источник
comment
Мне непонятно. Помогает ли установка расширений языка в подсказке? Я предполагаю, что нет, и назвал бы это ошибкой.   -  person Thomas M. DuBuisson    schedule 27.12.2019
comment
@ThomasM.DuBuisson: Нет, я только что попытался добавить set [languageExtensions := [DataKinds, TypeOperators]] в начало каждого монадного выражения интерпретатора; это не меняет поведение.   -  person ShapeOfMatter    schedule 27.12.2019


Ответы (1)


Не ответ, но я сделал некоторые открытия, которые могут оказаться полезными.

Я подумал, что это может быть фиктивный синтаксис оператора типа префикса ': x xs, который недействителен в Haskell (вам придется либо написать его как инфикс, либо использовать (':)). Поэтому я реализовал модуль-оболочку SemWorkaround, который использовал Cons и Nil вместо стандартного синтаксиса списка. Похоже, в основном та же проблема с более подробным сообщением об ошибке (хм).

Затем я подумал, что это может быть приложение явного вида, поскольку сообщения об ошибках продолжают говорить о том, что вещам дается слишком много аргументов. Поэтому я попытался изменить представление списка на уровне типов так, как мы делали это в старые времена.

{-# LANGUAGE DataKinds, TypeOperators, TypeFamilies #-}

module SemWorkaround where

import Polysemy (Sem, Embed)
import Data.Kind (Type)

data Nil 
data Cons (a :: (Type -> Type) -> Type -> Type) (as :: Type)

type family ListToList xs where
    ListToList Nil = '[]
    ListToList (Cons x xs) = x ': ListToList xs

newtype Sem' l a = Sem' { getSem' :: Sem (ListToList l) a }

И использовал Sem' для маршалирования границы подсказки. Например.

type MyEffect' = Sem' (Cons (Embed IO) Nil) ()

...

s <- interpret "Sem' . embed $ print \"Success\"" (as :: MyEffect')
pure $ getSem' s

Это сработало. Таким образом, кажется, что тот, кто создает тип, выдает явный аргумент типа для полиморфных поднятых конструкторов, но потребитель ожидает, что он будет неявным. Чтобы подтвердить, я изменил модуль обходного пути, чтобы использовать мономорфный тип данных List.

data List
    = Nil
    | Cons ((Type -> Type) -> Type -> Type) List

Что снова сработало.

Наконец, я проверил проблему с инфиксом, чтобы убедиться, изменив ее на:

data List
    = Nil
    | ((Type -> Type) -> Type -> Type) ::: List

Что, к моему удивлению, не удалось с вашим знакомым сообщением об ошибке Operator applied to too few arguments. Итак, кажется, вы нашли две ошибки. Кто-то не понимает поликиды, кому следует, а кто-то не понимает операторов типов, кому следует. Я не копал достаточно глубоко, чтобы выяснить, кто не прав.

person luqui    schedule 03.01.2020
comment
Привет @luqui; Я смог отследить это дальше: в основном Hint использует Show экземпляр TypeRef не по назначению (билет). Изменить подсказку таким образом, чтобы не указывать типовые характеристики, несложно, но как вы думаете, правильное ли это решение? - person ShapeOfMatter; 08.01.2020
comment
@ShapeOfMatter, я просматриваю эту ветку и благодарен вам обоим за помощь в улучшении всей экосистемы. - person luqui; 14.01.2020