Как установить условия внутри функции в 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)
...

Что я делаю не так?


person GeorgS    schedule 12.03.2019    source источник


Ответы (2)


Проблема здесь в том, что assert имеет нечистый эффект, поэтому его нельзя использовать в чистой функции, такой как mergeIou. Самый простой способ решить эту проблему — изменить mergeIou на тип Iou -> Iou -> Update Iou и поместить функцию в блок выполнения.

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.

person Recurse    schedule 13.03.2019

На самом деле есть способ определить все три версии mergeIou из ответа @Recurse за один раз, если вы используете класс типов ActionFail DAML:

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
person Martin Huschenbett    schedule 18.03.2019