haskell 为什么我的半群/幺半群示例重叠?

ct2axkht  于 2022-12-23  发布在  其他
关注(0)|答案(1)|浏览(151)

我试图实现一种方法来延迟构造非确定性有限自动机(NFA),我在F#中完成了years ago,现在想在利用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

这段代码无法编译,因为我的SemigroupMonoid示例与GHC.Base中的instance Semigroup b => Semigroup (a -> b)instance Monoid b => Monoid (a -> b)重叠,但我不明白为什么。
我看到函数a -> b上有一个Monoid示例,其中b本身就是Monoid,但是State没有Monoid示例,那么StateFState -> State)怎么会重叠呢?
是因为有人 * 可能 * 在其他地方为State实现Monoid吗?
还有,我该怎么解决这个问题?
我知道a可以将StateF定义为...

data StateF = StateF (State -> State)

......但这也会在模式匹配和构造StateF时增加语法噪声。
编译器错误:

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
   |          ^^^^^^^^^^^^^
jhdbpxl9

jhdbpxl91#

至少对于所示的代码,将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

-- This is another
connect :: StateF -> StateF -> StateF
connect fst snd = StateF $ complete fst . complete snd

-- This is a third
empty :: StateF
empty = StateF id

instance Semigroup StateF where
  (<>) = connect

instance Monoid StateF where
  mempty = empty

如果使用记录语法,则complete甚至不需要模式匹配:

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

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

(Don(不要把complete看作实际上把状态转换器 * 应用 * 到一个状态,而是 * 提取 * 状态转换器,以便它 * 可以 * 应用到一个状态。)

相关问题