了解纯脚本变体

Understanding purescript-variant

这里是新手。我正在尝试了解 purescript-variant. Basically what I mean is how to understand these 2 function: inj and on.

背后的一些机制

当我查看 inj 的类型时,作者使用了 Cons 类型类。根据我的理解,Cons 断言有一条记录 r2 可以通过插入一对 tag/value 从其他记录 r1 中得到。所以从某种意义上说:

r1 + tag/value = r2

在这种情况下 Variantr2

引用自述文件:

foo :: forall v. Variant (foo :: Int | v)
foo = inj (SProxy :: SProxy "foo") 42

bar :: forall v. Variant (bar :: Boolean | v)
bar = inj (SProxy :: SProxy "bar") true

fooToString :: forall v. Variant (foo :: Int | v) -> String
fooToString = on (SProxy :: SProxy "foo") show (\_ -> "not foo")

这就是让我感到困惑的地方。我可以将 bar 作为参数提供给 fooToString,而从 bar 的类型来看,即使它是开放类型,也不能保证它有一个标签 "foo"。这怎么可能?

foobar都限制变体类型必须包含一些标签,但它们不会阻止其他标签包含在变体中。应用 fooToString bar 时的具体类型为:

 bar :: Variant (bar :: Boolean, foo :: Int) -- v = (foo :: Int)
 fooToString :: Variant (foo :: Int, bar :: Boolean) -> String -- v = (bar :: Boolean)

如您所见,它们完全兼容。


类型的内部版本为

bar :: forall r1 r2. RowCons "bar" Boolean r1 r2 => Variant r2
fooToString :: forall r1 r2. RowCons "foo" Int r1 r2 => Variant r2 -> String

将专注于

bar :: RowCons "bar" Boolean (foo :: Int) (foo :: Int, bar :: Boolean) => Variant (foo :: Int, bar :: Boolean)
fooToString :: RowCons "foo" Int (bar :: Boolean) (foo :: Int, bar :: Boolean) => Variant (foo :: Int, bar :: Boolean) -> String

其中,对于barr1设置为to/specialized为(foo :: Int)r2变为(foo :: Int, bar :: Boolean)fooToString.

同样

如您所见,r1 在 bar 和 fooToString 的约束之外未使用,这允许自由选择它们以满足约束。编译器向类型添加更多(未使用的)变体同样有效,但这不会改变结果。


编辑:

Pruescript 的不寻常之处在于,不仅是函数,值也可以是多态的。在这种情况下,bar 是一个多态值,fooToString 是一个多态函数。这意味着 barfooToString 的用户都可以自由选择 v(或 r1/r2)的任何类型,只要类型包含所需的变体。