1

我有以下代码:

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)
...

我究竟做错了什么?

4

2 回答 2

3

如果您利用 DAML 的类型类,实际上有一种方法可以mergeIou一次性定义 @Recurse 答案的所有三个版本:ActionFail

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
于 2019-03-18T22:27:14.657 回答
1

这里的问题是assert具有不纯的效果,因此不能用于像mergeIou. 解决此问题的最简单方法是将mergeIou 更改为具有类型Iou -> Iou -> Update Iou并将函数放在do-block 中。

IE。

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

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

于 2019-03-13T23:53:14.290 回答