Функциональная зависимость с правилом специализации - PullRequest
4 голосов
/ 25 октября 2019

Я хочу написать правило переписывания специализации для комбинатора Megaparsec, чтобы правило срабатывало только тогда, когда тип ввода ByteString.

{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}

import Data.Void
import Text.Megaparsec
import qualified Data.ByteString as B

combin :: forall e s m a. (MonadParsec e s m)
    => m a
    -> m a
combin = label "String generic"

combinByteString :: forall e s m a. (MonadParsec e s m, s ~ B.ByteString)
    => m a
    -> m a
combinByteString = label "ByteString specialized"

main = do
    parseTest (combin empty :: Parsec Void String String) ""
    parseTest (combin empty :: Parsec Void B.ByteString String) ""

{-# NOINLINE combin #-}
{-# NOINLINE combinByteString #-}
{-# RULES "combin/ByteString" combin = combinByteString #-}

Когда я пытаюсьпостроить это не удалось:

$ cabal v2-run
Build profile: -w ghc-8.6.5 -O1
Main.hs:25:40: error:
    • Couldn't match type ‘s’ with ‘B.ByteString’
        arising from a functional dependency between constraints:
          ‘MonadParsec e B.ByteString m’
            arising from a use of ‘combinByteString’ at Main.hs:25:40-55
          ‘MonadParsec e s m’
            arising from the RULE "combin/ByteString" at Main.hs:25:11-55
      ‘s’ is a rigid type variable bound by
        the RULE "combin/ByteString"
        at Main.hs:25:11-55
    • In the expression: combinByteString
      When checking the transformation rule "combin/ByteString"
   |
25 | {-# RULES "combin/ByteString" combin = combinByteString #-}

Параметр типа входного потока s из MonadParsec имеет функциональную зависимость от параметра Monad m.

class (Stream s, MonadPlus m) => MonadParsec e s m | m -> e s where

Вот файл specialize.cabal для попытки сборки.

cabal-version:       >=1.10
name:                specialize
version:             0.1.0.0
build-type:          Simple

executable specialize
  main-is:             Main.hs
  build-depends:       base >= 4
                      ,megaparsec
                      ,bytestring
  default-language:    Haskell2010

В случае успеха вывод должен выглядеть следующим образом:

1:1:
  |
1 | <empty line>
  | ^
expecting String generic
1:1:
  |
1 | <empty line>
  | ^
expecting ByteString specialized

Совет?

1 Ответ

0 голосов
/ 26 октября 2019

Это правило работает, но только для GHC 8.8.1, но не для GHC 8.6.5.

{-# LANGUAGE TypeApplications #-}

{-# RULES "combin/ByteString" forall e. forall. 
    combin @e @B.ByteString = combinByteString @e @B.ByteString
#-}

Это правило работает с GHC 8.6.5 и 8.0.2

{-# RULES "combin/ByteString"
 forall (pa :: ParsecT e B.ByteString m a).
 combin @e @B.ByteString @(ParsecT e B.ByteString m) @a pa = 
 combinByteString @e @B.ByteString @(ParsecT e B.ByteString m) @a pa
#-}
...