如何证明可能的功能数量?

时间:2017-06-18 18:04:34

标签: haskell

查看函数声明,例如:

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)。我无法想象它,有很多实现。

如何在不写出来的情况下进行证明?

3 个答案:

答案 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 -> ca -> (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 -> QuadWord8之间也存在同构!

您也可以通过将产品类型(元组)扩展为和类型(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