haskell 为什么量化约束的这种用法无法编译:

tp5buhyn  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(114)

考虑以下情况:

{-# LANGUAGE QuantifiedConstraints #-}

data SomeMaybe c t where
  SomeNothing :: SomeMaybe c t
  SomeJust :: c t => t -> SomeMaybe c t

instance (forall b. c b => Semigroup b) => Semigroup (SomeMaybe c u) where
  x <> y = case x of
    SomeNothing -> y
    SomeJust x' -> case y of
      SomeNothing -> x
      SomeJust y' -> SomeJust (x' <> y')

我得到以下错误:

src/Filename.hs: error:
    • Could not deduce: c (SomeMaybe c u)
        arising from a use of ‘GHC.Base.$dmsconcat’
      from the context: forall b. c b => Semigroup b
        bound by the instance declaration
        at src/Filename.hs
    • In the expression: GHC.Base.$dmsconcat @(SomeMaybe c u)
      In an equation for ‘GHC.Base.sconcat’:
          GHC.Base.sconcat = GHC.Base.$dmsconcat @(SomeMaybe c u)
      In the instance declaration for ‘Semigroup (SomeMaybe c u)’
    • Relevant bindings include
        sconcat :: GHC.Base.NonEmpty (SomeMaybe c u) -> SomeMaybe c u
          (bound at src/Filename.hs)

我认为问题是sconcatstimes的默认实现无法进行类型检查。
但是我不太明白为什么会这样。

  • 背景说明:*

简单介绍一下为什么要创建像SomeMaybe这样的类型,我将数据类型设置为"barbies",这样就可以像这样使用bpure

instance ApplicativeB f => Semigroup (f MyType) where
  (<>) = bzipWith (<>)

instance ApplicativeB f => Monoid (f MyType) where
  mempty = bpure mempty

但这只适用于MyType a是所有a的幺半群。

编辑:解决方法

Semigroup定义更改为:

semigroupOp :: forall c t. (forall b. c b => Semigroup b) => SomeMaybe c t -> SomeMaybe c t -> SomeMaybe c t
semigroupOp x y = case x of
  SomeNothing -> y
  SomeJust x' -> case y of
    SomeNothing -> x
    SomeJust y' -> SomeJust (x' <> y')

instance forall c t. (forall b. c b => Semigroup b) => Semigroup (SomeMaybe c t) where
  (<>) :: (forall b. c b => Semigroup b) => SomeMaybe c t -> SomeMaybe c t -> SomeMaybe c t
  (<>) = semigroupOp
  sconcat :: NonEmpty (SomeMaybe c t) -> (SomeMaybe c t)
  sconcat (a :| as) = go a as where
    go :: SomeMaybe c t -> [SomeMaybe c t] -> SomeMaybe c t
    go x = \case
      [] -> x
      (c : cs) -> semigroupOp x (go c cs)
  stimes n = \case
    SomeNothing -> SomeNothing
    SomeJust x -> SomeJust (stimes n x)

它可以编译这个代码,虽然我不清楚为什么要这么做?特别是,为什么我不能在sconcat中调用<>而不是semigroupOp

g0czyy6m

g0czyy6m1#

从问题中删除,因为它是答案:
回答我自己的问题,将半群定义改为:

semigroupOp :: forall c t. (forall b. c b => Semigroup b) => SomeMaybe c t -> SomeMaybe c t -> SomeMaybe c t
semigroupOp x y = case x of
  SomeNothing -> y
  SomeJust x' -> case y of
    SomeNothing -> x
    SomeJust y' -> SomeJust (x' <> y')

instance forall c t. (forall b. c b => Semigroup b) => Semigroup (SomeMaybe c t) where
  (<>) :: (forall b. c b => Semigroup b) => SomeMaybe c t -> SomeMaybe c t -> SomeMaybe c t
  (<>) = semigroupOp
  sconcat :: NonEmpty (SomeMaybe c t) -> (SomeMaybe c t)
  sconcat (a :| as) = go a as where
    go :: SomeMaybe c t -> [SomeMaybe c t] -> SomeMaybe c t
    go x = \case
      [] -> x
      (c : cs) -> semigroupOp x (go c cs)
  stimes n = \case
    SomeNothing -> SomeNothing
    SomeJust x -> SomeJust (stimes n x)

解决了这个问题。

相关问题