在这些选项之间进行选择的实际原因是什么?
例如:
foreign import data Foo :: Type -> Type
newtype Foo a = Foo a
在两种情况下我们都假设,我们通过一些函数得到一个Foo:
foreign import newFoo :: forall a. a -> Foo a
答案 0 :(得分:4)
区别在于,使用newtype
时,数据表示是已知的,而使用foreign import
时,则不是。
一个结果是,使用newtype
,您可以通过模式匹配从a
中获得Foo a
:
let foo = newFoo 42
let (Foo fourtyTwo) = foo
使用foreign import
不能做到这一点。
另一个结果是,使用foreign import
函数newFoo
可以自由选择表示形式,它不一定必须与a
等效,例如:
// JavaScript
exports.newFoo = function (a) { return { wrapped: a } }
但必须与newtype
正好为a
:
// JavaScript
exports.newFoo = function (a) { return a }
然后还有自动派生Newtype
类的便利,这提供了一些自动化的可能性。
要回答评论中的第二个问题(以后请再发表一个问题):
如果您的Foo
没有类型参数,但定义如下:
// Case 1
data Foo = Foo
// Case 2
foreign import data Foo :: Type
foreign import newFoo :: Foo
这里的区别与上述相同:对于data
表示是已知的,对于foreign import
则不是。
它在实践中表现出来的方式实际上取决于您的上下文。我能想到的一个示例是Eq
,Show
,Generic
等的自动派生,对于foreign import
方法,需要对其进行手动编码。想到的另一个示例是,data Foo
被静态保证具有一个唯一值,而newFoo
可以在每次调用中自由返回不同的值。