简体   繁体   English

为什么我的 Semigroup/Monoid 实例重叠?

[英]Why is my Semigroup/Monoid instance overlapping?

I'm trying to implement a way to lazily construct nondeterministic finite automata (NFAs).我正在尝试实现一种延迟构造非确定性有限自动机 (NFA) 的方法。 I did this years ago in F# and now want to try it with Haskell while leveraging the Monoid typeclass.几年前在 F# 中做过这件事,现在想在利用Monoid类型类的同时尝试使用 Haskell。

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}

module NFA where

data State = State Match State | Split State State | Final deriving (Show)
data Match = Any | Char Char | ... deriving (Show)

type StateF = State -> State

complete :: StateF -> State -> State
complete statef exit = statef exit

connect :: StateF -> StateF -> StateF
connect fst snd = complete fst . complete snd

empty :: StateF
empty = id

instance Semigroup StateF where
  (<>) = connect

instance Monoid StateF where
  mempty = empty

This code doesn't compile, because my Semigroup and Monoid instances are overlapping with instance Semigroup b => Semigroup (a -> b) and instance Monoid b => Monoid (a -> b) from GHC.Base , but I don't understand why.此代码无法编译,因为我的SemigroupMonoid实例与来自GHC.Base的实例 Semigroup b => Semigroup (a instance Semigroup b => Semigroup (a -> b)instance Monoid b => Monoid (a -> b)重叠,但我不这样做不明白为什么。

I see that there is a Monoid instance on functions a -> b , where b is a Monoid itself.我看到函数a -> b上有一个Monoid实例,其中bMonoid本身。 But State doesn't have a Monoid instance, so how can StateF ( State -> State ) overlap?但是State没有Monoid实例,那么StateF ( State -> State ) 怎么重叠呢?

Is it because someone might implement Monoid for State elsewhere?是因为有人可能会在其他地方为State实现Monoid吗?

Also, how can I fix this?另外,我该如何解决这个问题?

I'm aware that a could just define StateF as...我知道 a 可以将StateF定义为...

data StateF = StateF (State -> State)

...but that would also increase syntax noise when pattern matching and constructing StateF s. ...但这也会在模式匹配和构造StateF时增加语法噪音。

The comiler errors:编译器错误:

src\NFA.hs:10:10: error:
    * Overlapping instances for Semigroup StateF
        arising from a use of `GHC.Base.$dmsconcat'
      Matching instances:
        instance Semigroup b => Semigroup (a -> b) -- Defined in `GHC.Base'
        instance Semigroup StateF -- Defined at src\NFA.hs:10:10
    * In the expression: GHC.Base.$dmsconcat @(StateF)
      In an equation for `GHC.Base.sconcat':
          GHC.Base.sconcat = GHC.Base.$dmsconcat @(StateF)
      In the instance declaration for `Semigroup StateF'
   |
10 | instance Semigroup StateF where
   |          ^^^^^^^^^^^^^^^^

src\NFA.hs:10:10: error:
    * Overlapping instances for Semigroup StateF
        arising from a use of `GHC.Base.$dmstimes'
      Matching instances:
        instance Semigroup b => Semigroup (a -> b) -- Defined in `GHC.Base'
        instance Semigroup StateF -- Defined at src\NFA.hs:10:10
    * In the expression: GHC.Base.$dmstimes @(StateF)
      In an equation for `GHC.Base.stimes':
          GHC.Base.stimes = GHC.Base.$dmstimes @(StateF)
      In the instance declaration for `Semigroup StateF'
   |
10 | instance Semigroup StateF where
   |          ^^^^^^^^^^^^^^^^

src\NFA.hs:13:10: error:
    * Overlapping instances for Semigroup StateF
        arising from the superclasses of an instance declaration
      Matching instances:
        instance Semigroup b => Semigroup (a -> b) -- Defined in `GHC.Base'
        instance Semigroup StateF -- Defined at src\NFA.hs:10:10
    * In the instance declaration for `Monoid StateF'
   |
13 | instance Monoid StateF where
   |          ^^^^^^^^^^^^^

src\NFA.hs:13:10: error:
    * Overlapping instances for Monoid StateF
        arising from a use of `GHC.Base.$dmmappend'
      Matching instances:
        instance Monoid b => Monoid (a -> b) -- Defined in `GHC.Base'
        instance Monoid StateF -- Defined at src\NFA.hs:13:10
    * In the expression: GHC.Base.$dmmappend @(StateF)
      In an equation for `mappend':
          mappend = GHC.Base.$dmmappend @(StateF)
      In the instance declaration for `Monoid StateF'
   |
13 | instance Monoid StateF where
   |          ^^^^^^^^^^^^^

src\NFA.hs:13:10: error:
    * Overlapping instances for Monoid StateF
        arising from a use of `GHC.Base.$dmmconcat'
      Matching instances:
        instance Monoid b => Monoid (a -> b) -- Defined in `GHC.Base'
        instance Monoid StateF -- Defined at src\NFA.hs:13:10
    * In the expression: GHC.Base.$dmmconcat @(StateF)
      In an equation for `mconcat':
          mconcat = GHC.Base.$dmmconcat @(StateF)
      In the instance declaration for `Monoid StateF'
   |
13 | instance Monoid StateF where
   |          ^^^^^^^^^^^^^

At least for the code shown, changing StateF from a type alias to a newtype introduces minimal changes and no runtime overhead.至少对于显示的代码,将StateF从类型别名更改为新类型newtype引入最小的更改并且没有运行时开销。

module NFA where

data State = State Match State | Split State State | Final deriving (Show)
data Match = Any | Char Char | ... deriving (Show)

newtype StateF = StateF (State -> State)

-- This is one change
complete :: StateF -> State -> State
complete (StateF f) = f

connect :: StateF -> StateF -> StateF
connect fst snd = complete fst . complete snd

-- This is the other
empty :: StateF
empty = StateF id

instance Semigroup StateF where
  (<>) = connect

instance Monoid StateF where
  mempty = empty

If you use record syntax, you won't even need pattern-matching for complete :如果你使用记录语法,你甚至不需要模式匹配来complete

newtype StateF  = StateF { runStateF :: State -> State }

complete :: StateF -> State -> State
-- complete statef exit = runStateF statef exit
-- complete statef = runStateF statef
complete = runStateF

(Don't think of complete as actually applying the state transformer to a state, but rather extracting the state transformer so that it can be applied to a state.) (不要将complete视为实际状态转换器应用于状态,而是提取状态转换器以便将其应用于状态。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM