了解纯脚本变体
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
在这种情况下 Variant
是 r2
。
引用自述文件:
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"。这怎么可能?
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
其中,对于bar
,r1
设置为to/specialized为(foo :: Int)
,r2
变为(foo :: Int, bar :: Boolean)
。 fooToString
.
同样
如您所见,r1 在 bar 和 fooToString 的约束之外未使用,这允许自由选择它们以满足约束。编译器向类型添加更多(未使用的)变体同样有效,但这不会改变结果。
编辑:
Pruescript 的不寻常之处在于,不仅是函数,值也可以是多态的。在这种情况下,bar
是一个多态值,fooToString
是一个多态函数。这意味着 bar
和 fooToString
的用户都可以自由选择 v
(或 r1
/r2
)的任何类型,只要类型包含所需的变体。
这里是新手。我正在尝试了解 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
在这种情况下 Variant
是 r2
。
引用自述文件:
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"。这怎么可能?
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
其中,对于bar
,r1
设置为to/specialized为(foo :: Int)
,r2
变为(foo :: Int, bar :: Boolean)
。 fooToString
.
如您所见,r1 在 bar 和 fooToString 的约束之外未使用,这允许自由选择它们以满足约束。编译器向类型添加更多(未使用的)变体同样有效,但这不会改变结果。
编辑:
Pruescript 的不寻常之处在于,不仅是函数,值也可以是多态的。在这种情况下,bar
是一个多态值,fooToString
是一个多态函数。这意味着 bar
和 fooToString
的用户都可以自由选择 v
(或 r1
/r2
)的任何类型,只要类型包含所需的变体。