首页 > 解决方案 > 了解纯脚本变体

问题描述

新手来了 我试图了解purescript-variant背后的一些机制。基本上我的意思是如何理解这两个函数:injon

当我查看 的类型时inj,作者使用了Cons类型类。据我了解,Cons断言可以通过插入一对标签/值r2从其他记录中创建一条记录。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")

这就是让我感到困惑的地方。我可以将 thebar作为参数提供给fooToStringwhile 的类型,bar即使它是开放类型,也不能保证它具有标签“foo”。这怎么可能?

标签: purescript

解决方案


两者都foo限制bar变体类型必须包含一些标签,但它们不会阻止其他标签包含在变体中。申请时的具体类型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被设置/专门化为(foo :: Int)r2成为(foo :: Int, bar :: Boolean)。同样对于fooToString

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


编辑:

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


推荐阅读