【问题标题】:Why does a sum-type of `a` containing a list constructor not match a list of `a`?为什么包含列表构造函数的“a”和类型与“a”列表不匹配?
【发布时间】:2018-09-02 03:54:29
【问题描述】:

我正在尝试实现primitive recursive functions。显然在 Haskell 中使用可变参数函数并不常见,我使用了一个类型

data PrimT a = Sgl a | Sqc [a]

所以我可以将原子值和值列表传递给函数。这适用于零函数、投影和后继函数:

zero k (Sqc args) = if length args == k then Right 0 else Left "invalid number of arguments"
zero 1 (Sgl arg)  = Right 0

pi i k (Sqc args) = if length args == k then Right $ args!!i else Left "invalid number of arguments"
pi 1 1 (Sgl arg) = Right arg

nu (Sgl i) = Sgl $ i + 1

但是我遇到了构图问题(这里是o)。这个定义背后的想法是组合可以发生在函数 f 和:1)函数列表和参数列表,2)函数列表和一个参数,3)一个函数和一个参数列表,最后 4 ) 一个函数和一个参数。因此,我将函数和PrimT 放在了Sqc gs 的函数列表和Sgl g 的单个函数中。参数相同:Sqc argsSgl arg

o :: PrimT (PrimT b -> PrimT c) -> PrimT (PrimT a -> PrimT b) -> PrimT a -> PrimT c
o (Sgl f) (Sqc gs) (Sqc args) = f [g args | g <- gs]
-- o (Sgl f) (Sqc gs) (Sgl arg) = f [g arg | g <- gs]
-- o (Sgl f) (Sgl g) (Sqc args) = f [g args]
-- o (Sgl f) (Sgl g) (Sgl arg) = f [g arg]

但是编译器对f [g args | g &lt;- gs] 部分不满意。它说:

primrec.hs:69:35: error:
    • Couldn't match expected type ‘PrimT b’
                  with actual type ‘[PrimT b]’
    • In the first argument of ‘f’, namely ‘[g args | g <- gs]’
      In the expression: f [g args | g <- gs]
      In an equation for ‘o’:
          o (Sgl f) (Sqc gs) (Sqc args) = f [g args | g <- gs]
    • Relevant bindings include
        gs :: [PrimT a -> PrimT b] (bound at primrec.hs:69:16)
        f :: PrimT b -> PrimT c (bound at primrec.hs:69:8)
        o :: PrimT (PrimT b -> PrimT c)
             -> PrimT (PrimT a -> PrimT b) -> PrimT a -> PrimT c
          (bound at primrec.hs:69:1)
   |
69 | o (Sgl f) (Sqc gs) (Sqc args) = f [g args | g <- gs]
   |                                   ^^^^^^^^^^^^^^^^^^

primrec.hs:69:38: error:
    • Couldn't match expected type ‘PrimT a’ with actual type ‘[a]’
    • In the first argument of ‘g’, namely ‘args’
      In the expression: g args
      In the first argument of ‘f’, namely ‘[g args | g <- gs]’
    • Relevant bindings include
        g :: PrimT a -> PrimT b (bound at primrec.hs:69:45)
        args :: [a] (bound at primrec.hs:69:25)
        gs :: [PrimT a -> PrimT b] (bound at primrec.hs:69:16)
        o :: PrimT (PrimT b -> PrimT c)
             -> PrimT (PrimT a -> PrimT b) -> PrimT a -> PrimT c
          (bound at primrec.hs:69:1)
   |
69 | o (Sgl f) (Sqc gs) (Sqc args) = f [g args | g <- gs]
   |

但我不明白为什么。 PrimT a 根据其定义可以是a ([a]) 的列表。那么问题出在哪里?

【问题讨论】:

  • Just 'x''x' 不同。 CharMaybe Char 的类型不同。
  • 如果不进一步解释您所指的内容,则无济于事。
  • fwiw,你遇到了所有这些问题,因为你试图绕过类型系统。单个值与值列表不同。你不能只是互换使用它们。当您通过添加第三种类型来解决此问题时,您现在涉及 三种 类型,而不是两种。
  • @Carl 但是将单例列表用于原子值似乎是错误的。
  • Sgl xSqc [x] 的语义区别是什么?如果没有,为什么你允许两者?

标签: haskell types algebraic-data-types


【解决方案1】:

PrimT a 根据其定义可以是a ([a]) 的列表

不,PrimT a 可以是 SglSqc。所以给定一个[a] 类型的列表xsSqc xs 将是PrimT a,但xs 不会。 xs 已经是一个列表——它不可能是别的东西。

按照同样的逻辑,Sqc argsPrimT aSqc [g (Sqc args) | g &lt;- gs]PrimT (PrimT b),但如果没有 Sqc,它们只是列表。

我还应该指出 PrimT (PrimT b) 不是您想要的类型(您想要 PrimT b),因此您仍然需要将结果展平才能得到您想要的。

【讨论】:

  • 好的,所以我明白为什么将Sqc 放在列表理解前面是必要的。但我不明白为什么在函数体内的args 前面有必要。
  • @lotolmencre 我们没有g :: [a] -&gt; ...,只有g :: PrimT a -&gt; ...,所以我们需要传递一个正确类型的值。
  • @chi 但g 的类型为PrimT a -&gt; PrimT b,而args 的类型为PrimT a。所以……我还是不明白。
  • @lotolmencre 否,Sqc args 的类型为 PrimT aargs 的类型为 [a]
  • @lotolmencre Sqc [SomeType] 的类型为 PrimT SomeType[g (Sqc args) | g &lt;- gs] 的类型为 [PrimT b],因此在这种情况下,SomeTypePrimT bSqc [g (Sqc args) | g &lt;- gs] 的类型为 PrimT (PrimT b)
猜你喜欢
  • 2017-07-18
  • 1970-01-01
  • 2016-11-20
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 2012-02-13
相关资源
最近更新 更多