存在型でSMLのシグネチャを模倣する

SML で

```sml
signature SIG = sig
  type t
  val zero : t
end
structure IntStr :> SIG = struct
  type t = int
  val zero = 0
end
structure RealStr :> SIG = struct
  type t = real
  val zero = 0.0
end
```

のようにするところを， Haskell では

```hs
{-# LANGUAGE ExistentialQuantification #-}
data SIG = forall t. Struct { zero :: t }
intStr :: SIG
intStr = Struct 0
realStr :: SIG
realStr = Struct 0.0
```

のように書ける．

* HaskellのSIG型がシグネチャ，
* SIG型の値がストラクチャ，
* SIG型による型注釈が不透明な制約(opaque constraint)

に対応．

なお，レコードなので当然第一級モジュールになっていて，かつ，関数がそのままファンクタとして扱える．

透明な制約(transparent constraint)はできないかも．

シグネチャの include やストラクチャの open などはできない．

『型システム入門』の24章などを参考

例

```hs
{-# LANGUAGE ExistentialQuantification  #-}
{-# LANGUAGE NamedFieldPuns             #-}

data LATTICE = forall t. Eq t => MkLattice {
                  one :: t,
                  zero :: t,
                  ljoin :: t -> t -> t,
                  lmeet :: t -> t -> t
                }

boolLattice :: LATTICE
boolLattice = MkLattice True False (||) (&&)

intMin :: Int -> Int -> Int
intMin = min

intMax :: Int -> Int -> Int
intMax = max

intLattice :: LATTICE
intLattice = MkLattice 1 0 intMin intMax

data TEST_LATTICE = forall t. Eq t => MkTestLattice {
                      tone :: t,
                      tzero :: t,
                      tljoin :: t -> t -> t,
                      tlmeet :: t -> t -> t,
                      idempotence :: t -> Bool,
                      commutativity :: t -> t -> Bool,
                      associativity :: t -> t -> t -> Bool,
                      absorption :: t -> t -> Bool
                    }

testLatticeFunctor :: LATTICE -> TEST_LATTICE
testLatticeFunctor (MkLattice {one, zero, ljoin, lmeet}) = MkTestLattice {
                      tone = one,
                      tzero = zero,
                      tljoin = ljoin,
                      tlmeet = lmeet,
                      idempotence = \x -> lmeet x x == x && ljoin x x == x && lmeet x x == ljoin x x,
                      commutativity = \x y -> lmeet x y == lmeet y x && ljoin x y == ljoin y x,
                      associativity = \x y z -> lmeet (lmeet x y) z == lmeet x (lmeet y z) &&
                                              ljoin (ljoin x y) z == ljoin x (ljoin y z),
                      absorption = \x y -> ljoin (lmeet x y) x == x && lmeet (ljoin x y) x == x
                    }

boolLatticeTester :: TEST_LATTICE
boolLatticeTester = testLatticeFunctor boolLattice

intLatticeTester :: TEST_LATTICE
intLatticeTester = testLatticeFunctor intLattice

checkAll :: TEST_LATTICE -> IO ()
checkAll latticeTester = do
  case latticeTester of
    (MkTestLattice {tone, tzero, tljoin, tlmeet, idempotence, commutativity, associativity, absorption}) -> do
      print (idempotence tone)
      print (idempotence tzero)
      print (commutativity tone tone)
      print (commutativity tone tzero)
      print (commutativity tzero tone)
      print (commutativity tzero tzero)
      print (associativity tone tone tone)
      print (associativity tone tone tzero)
      print (associativity tone tzero tone)
      print (associativity tzero tone tone)
      print (associativity tzero tone tzero)
      print (associativity tzero tzero tone)
      print (absorption tone tone)
      print (absorption tone tzero)
      print (absorption tzero tone)
      print (absorption tzero tzero)


main :: IO ()
main = do
  checkAll boolLatticeTester
  checkAll intLatticeTester
```

```sml
signature LATTICE = sig
  eqtype t
  val one : t
  val zero : t
  val ljoin : t * t -> t
  val lmeet : t * t -> t
end

structure IntLattice :> LATTICE = struct
  type t = int
  val one = 1
  val zero = 0
  val ljoin = Int.min
  val lmeet = Int.max
end

structure BoolLattice :> LATTICE = struct
  type t = bool
  val one = true
  val zero = false
  fun ljoin(x, y) = x orelse y
  fun lmeet(x, y) = x andalso y
end

signature LATTICE_TESTER = sig
  eqtype t
  val tone : t
  val tzero : t
  val tljoin : t * t -> t
  val tlmeet : t * t -> t
  val idempotence : t -> bool
  val commutativity : t * t -> bool
  val associativity : t * t * t -> bool
  val absorption : t * t -> bool
  val checkAll : unit -> unit
end

functor LatticeTester(Lattice : LATTICE) :> LATTICE_TESTER = struct
  type t = Lattice.t
  val tone = Lattice.one
  val tzero = Lattice.zero
  val tljoin = Lattice.ljoin
  val tlmeet = Lattice.lmeet
  fun idempotence x =
    let open Lattice in lmeet(x, x) = x andalso ljoin(x, x) = x andalso lmeet(x, x) = ljoin(x, x) end
  fun commutativity(x, y) =
    let open Lattice in lmeet(x, y) = lmeet(y, x) andalso ljoin(x, y) = ljoin(y, x) end
  fun associativity(x, y, z) =
    let open Lattice in lmeet(lmeet(x, y), z) = lmeet(x, lmeet(y, z)) andalso
                                  ljoin(ljoin(x, y), z) = ljoin(x, ljoin(y, z)) end
  fun absorption(x, y) =
    let open Lattice in ljoin(lmeet(x, y), x) = x andalso lmeet(ljoin(x, y), x) = x end

  fun printBool x = print (Bool.toString x)

  fun checkAll() = (
    printBool(idempotence tone);
    printBool(idempotence tzero);
    printBool(commutativity(tone, tone));
    printBool(commutativity(tone, tzero));
    printBool(commutativity(tzero, tone));
    printBool(commutativity(tzero, tzero));
    printBool(associativity(tone, tone, tone));
    printBool(associativity(tone, tone, tzero));
    printBool(associativity(tone, tzero, tone));
    printBool(associativity(tzero, tone, tone));
    printBool(associativity(tzero, tone, tzero));
    printBool(associativity(tzero, tzero, tone));
    printBool(absorption(tone, tone));
    printBool(absorption(tone, tzero));
    printBool(absorption(tzero, tone));
    printBool(absorption(tzero, tzero)))
end

structure BoolLatticeTester = LatticeTester(BoolLattice)
structure IntLatticeTester = LatticeTester(IntLattice)

structure Test = struct

  fun main _ = (
    BoolLatticeTester.checkAll();
    IntLatticeTester.checkAll();
    0)
end
```

## 参考文献

* Pierce, Benjamin C. (2013) 『型システム入門』 住井英二郎監訳, 遠藤侑介ほか訳, オーム社.
* [7.4.6. Existentially quantified data constructors - GHC User's Guide, Version 7.8.4](https://downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/data-type-extensions.html#existential-quantification) 2014年12月19日アクセス.
* [Haskell/存在量化された型](http://ja.wikibooks.org/wiki/Haskell/%E5%AD%98%E5%9C%A8%E9%87%8F%E5%8C%96%E3%81%95%E3%82%8C%E3%81%9F%E5%9E%8B) 2014年12月19日アクセス.