查看函数声明,例如:
myFoo :: Bool -> Bool
我可以说,函数myFoo
有四种可能的唯一实现,因为函数类型是指数运算符,这里是上面2^2 = 4
案例的证明:
myFoo1 :: Bool -> Bool
myFoo1 True = False
myFoo1 True = True
myFoo2 :: Bool -> Bool
myFoo2 False = False
myFoo2 False = True
我如何进行以下数据声明:
data Quad =
One
| Two
| Three
| Four
deriving (Eq, Show)
以及以下功能:
funcQuad :: Quad -> Quad
可能的实施是256(4^4)
。我无法想象它,有很多实现。
如何在不写出来的情况下进行证明?
答案 0 :(得分:7)
您可以使用类型代数来计算某种类型的居民数量。
有3种主要类型结构:
Either a b
,在类型代数中写为+ b (a, b)
,在类型代数中写为×b a -> b
,在类型代数中写为b a 还有一些基本类型,例如单位类型()
,写为1
,荒谬类型Void
,写为0
。
大多数常见代数在类型代数(分布,交换,幂等等)中工作,这就是“代数数据类型”这个名称的来源。结果表达式的基本含义是您的类型的居民数量。平等可以转化为类型世界中的同构。
对于像你这样的枚举(即nullary构造函数的联合),我们通常将1 + 1 + ... + 1
写为n
1
s,给定n
构造函数的数量
此处,您的Quad
类型在类型代数中转换为1 + 1 + 1 + 1
,并且可以缩小为4
。然后,您的Quad -> Quad
类型写为4 4 ,即256。
答案 1 :(得分:3)
函数 f:A→B 映射值x↦f(x)。鉴于 A 和 B 是有限集,比可能的函数数量限制为 | B | | A |
我们可以通过简单的组合学证明这一点。对于每个x∈A,有 | B | 可能的值来映射 f(x)。对于每个这样的 x ,我们可以独立地选择一个值b∈B,因此可能值的总数是 | B |。 ×| B | ×......×| B | = | B | | A |
对于Quad
类型,如果您构建函数f :: Quad -> Quad
,则 A = B = Quad
。这意味着 | A | = | B | = 4 (因为有四个可能的值,没有参数)。这意味着有 4 4 = 256 的可能性。
功能g :: Quad -> Bool
的数量因此为16:因为 A = Quad
且 B = Bool
,这意味着 | A | = 4 和 | B | = 2 ,因此可能的函数数量为2 4 = 16。这些如下:
g01 One = False
g01 Two = False
g01 Three = False
g01 Four = False
g02 One = False
g02 Two = False
g02 Three = False
g02 Four = True
g03 One = False
g03 Two = False
g03 Three = True
g03 Four = False
g04 One = False
g04 Two = False
g04 Three = True
g04 Four = True
g05 One = False
g05 Two = True
g05 Three = False
g05 Four = False
g06 One = False
g06 Two = True
g06 Three = False
g06 Four = True
g07 One = False
g07 Two = True
g07 Three = True
g07 Four = False
g08 One = False
g08 Two = True
g08 Three = True
g08 Four = True
g09 One = True
g09 Two = False
g09 Three = False
g09 Four = False
g10 One = True
g10 Two = False
g10 Three = False
g10 Four = True
g11 One = True
g11 Two = False
g11 Three = True
g11 Four = False
g12 One = True
g12 Two = False
g12 Three = True
g12 Four = True
g13 One = True
g13 Two = True
g13 Three = False
g13 Four = False
g14 One = True
g14 Two = True
g14 Three = False
g14 Four = True
g15 One = True
g15 Two = True
g15 Three = True
g15 Four = False
g16 One = True
g16 Two = True
g16 Three = True
g16 Four = True
最后,人们可以询问函数f :: a -> b -> c
的数量。 a -> b -> c
是a -> (b -> c)
的缩写。函数f :: Quad -> (Quad -> Bool)
的数量。由于函数Quad -> Bool
的数量为16,因此这意味着 A = Quad
和 B = (Quad -> Bool)
因此 | A | = 4 和 | B | = 16 。这导致总共 16 4 = 65 536 可能的函数。由于可能的实现数量增长得非常快,因此详尽地列举它们将很容易变得不可行。
答案 2 :(得分:3)
您同意Quad
= 4和Quad -> Quad
= 4 4 。所以让我们做一个小代数来说服自己,类型为Quad -> Quad
的函数有256种可能的实现。
4 4 = 4×4×4×4。在类型中,这将是(Quad, Quad, Quad, Quad)
。我们可以明确地将同构作为一对Haskell函数写出来:
type Quad4 = (Quad, Quad, Quad, Quad)
tupleToFunction :: Quad4 -> (Quad -> Quad)
tupleToFunction (a, b, c, d) x = case x of
One -> a
Two -> b
Three -> c
Four -> d
functionToTuple :: (Quad -> Quad) -> Quad4
functionToTuple f = (f One, f Two, f Three, f Four)
现在,这就是诀窍:您可以将Quad4
视为基数4中的4位数字,范围从0000 4 = 0 = (One, One, One, One)
到3333 < sub> 4 = 255 = (Four, Four, Four, Four)
。
这些数字中的每一个代表一种可能的实施方式。我们可以通过选择一个数字并将其用作输出来将数字转换为实现;我们可以通过将所有可能的输出“打包”到数字的数字中来将实现转换为数字。所以Quad -> Quad
和Word8
之间也存在同构!
您也可以通过将产品类型(元组)扩展为和类型(Either
)来实现此目的。对于Quad
来说,这将是巨大的,但这是你用Bool -> Bool
= 2 2 = 2×2 = 2 + 2:
type BB = Either Bool Bool
eitherToFunction :: BB -> (Bool -> Bool)
eitherToFunction (Left a) _ = a
eitherToFunction (Right a) b = a == b -- xnor
现在,我们可以将const True
表示为Left True
,将const False
表示为Left False
,将id
表示为Right True
,将not
表示为Right False
,我们相应地写了同构的另一半:
functionToEither :: (Bool -> Bool) -> BB
functionToEither f
| f True && f False = Left True
| f True = Right True
| f False = Right False
| otherwise = Left False