Я хочу написать правило перезаписи специализации для комбинатора 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
Совет?
s
вытекало изm
, поэтому у вас не может быть разныхs
(String
илиByteString
) для одного и того жеm
. Пробовали ли вы вместо этого исправитьm
, напримерm ~ Parsec e ByteString a
? - person Fyodor Soikin   schedule 25.10.2019m
способами, подобными тому, что вы предлагаете, и я все еще не могу заставить его собраться, и даже если бы он построился, это было бы не совсем правильно, потому что я хочу, чтобы это работало для всех экземплярыMonadParsec
, а не толькоParsecT
. - person James Brock   schedule 25.10.2019RULE
? Можете ли вы вместо этого сделать класс типов? - person Fyodor Soikin   schedule 25.10.2019combin
. Я не хочу добавлять какие-либо специальные ограничения класса в общедоступный API. - person James Brock   schedule 25.10.2019ifcxt
- person Fyodor Soikin   schedule 25.10.2019