如何在 DAML 中的函数内断言条件?

How do I assert conditions inside a function in DAML?

我有以下代码:

template Iou
  with
    issuer : Party
    owner : Party
    amount : Decimal
    currency : Text
  where
    signatory issuer

mergeIou : Iou -> Iou -> Iou
mergeIou a b =
--  assert $ a.issuer == b.issuer
--  assert $ a.owner == b.owner
--  assert $ a.currency == b.currency
  a with amount = a.amount + b.amount

当我取消注释任何断言时,出现以下错误:

* Couldn't match expected type `Iou' with actual type `m0 ()'
    * In the expression:
        assert
          $ (DA.Internal.Record.getField @"issuer" a)
...

我做错了什么?

这里的问题是assert有一个不纯的效果,所以不能用在纯 功能类似于 mergeIou。解决这个问题最简单的方法是改变 mergeIou 具有类型 Iou -> Iou -> Update Iou 并将函数放在 做块。

mergeIou : Iou -> Iou -> Update Iou
mergeIou a b = do
  assert $ a.issuer == b.issuer
  assert $ a.owner == b.owner
  assert $ a.currency == b.currency
  pure $ a with amount = a.amount + b.amount

如果你需要的功能是纯粹的,就不能使用assert。最简单的 另一种方法是使用 Optional 在类型中明确显示失败:

mergeIou : Iou -> Iou -> Optional Iou
mergeIou a b = do
  unless (a.issuer == b.issuer) None
  unless (a.owner == b.owner) None
  unless (a.currency == b.currency) None
  pure $ a with amount = a.amount + b.amount

为了帮助调试,我建议您改用 Either,这样您就可以 确定哪个断言失败:

mergeIou : Iou -> Iou -> Either Text Iou
mergeIou a b = do
  unless (a.issuer == b.issuer) $ Left "IOU issuers did not match"
  unless (a.owner == b.owner) $ Left "IOU owners did not match"
  unless (a.currency == b.currency) $ Left "IOU currencies did not match"
  pure $ a with amount = a.amount + b.amount

为了更全面地讨论这里到底发生了什么,我建议你 阅读我对 Trouble using the getTime 的扩展回答 函数 我在这里讨论纯度和封装分类帐的概念 DAML 中的交互。

如果您利用 DAML 的 ActionFail 类型 class:

,实际上有一种方法可以从@Recurse 的回答中一次定义所有三个版本的 mergeIou
mergeIou : ActionFail m => Iou -> Iou -> m Iou
mergeIou a b = do
  unless (a.issuer == b.issuer) $ fail "IOU issuers did not match"
  unless (a.owner == b.owner) $ fail "IOU owners did not match"
  unless (a.currency == b.currency) $ fail "IOU currencies did not match"
  pure $ a with amount = a.amount + b.amount