structural subtyping vs. nominal subtyping

structural subtypingは、Cleanにはないのだったということを思い出した。type classには明示的に継承関係を記述する必要があるので、nominal subtypingの一種だよね。
structural subtypingといえばOCamlだと思うのだけれど、それよりも、動的型チェック言語でよく言われるメリットであるところのduck typingって、structural subtypingとよく似ていると思うのだけれど、structural subtypingがコードの可読性を下げるのなら、duck typingなんてもっと下げちゃうよね、と思った。

      • -

まてよ。Cleanにもstructural subtypingはあるぞ。レコード型に対するそれはないけれど、関数型に対するそれはある。どう書けばテストできるのかよく分からなくてあれこれ悩んだのですが、下のようにして確認。

class A a where fa :: a -> Int
class B a | A a where fb :: a -> Int
class C a | B a where fc :: a -> Int

::Ta = {a::Int}
::Tb = {a::Int, b::Int}
::Tc = {a::Int, b::Int, c::Int}

instance A Ta where fa {Ta|a} = a
instance A Tb where fa {Tb|a} = a
instance A Tc where fa {Tc|a} = a

instance B Tb where fb {Tb|b} = b
instance B Tc where fb {Tc|b} = b

instance C Tc where fc {Tc|c} = c

f0 :: a -> Tb | B a // & B b
f0 x = {Tb|a=fa x, b=fb x}

ap :: (a -> b) a -> (Int, Int) | C a & A b
ap f a = (fa (f a), fc a)

Start = ap f0 {Tc|a=0,b=1,c=2}

なお、f0でコメントアウトになっているところは、「f0 :: a -> b | B a & B b」とすると、型チェックでエラーになるので、それを回避したもの。