tldr: Для @bame вам необходимо связать результат getTime
в Update
или Scenario
do-block.т.е.
Add_Car : CarId
with
startCoverage: Time
do
-- Check for a legal start date
now <- getTime
assert $ startCoverage > now
create this with datetime_vehicle_added = startCoverage, covered=True
Чтобы понять, что здесь произошло, нам нужно начать с типа getTime
:
getTime : (HasTime m) => m Time
Сигнатура типа ожидаемой функции - одна из:
getTimeValue : Time
getTimeFunc : () -> Time
Чтобы понять разницу, вам нужно рассмотреть понятия чистоты и инкапсуляции.
Чистота
В DAML все функции чистые.
Чистая функция - это функция, которая может быть полностью описана в терминах отображения значений, передаваемых в качестве аргументов, значениям, возвращаемым в результате.Значения - это конкретные вещи, такие как Time, Int, Text и т. Д., Списки, записи и варианты значений, а также некоторые другие вещи, о которых я расскажу позже.getTimeValue
- это значение, поэтому оно по определению является константой, которая будет только «текущим временем» в смысле «остановленных часов».
getTimeFunc
- это функция, которая принимает аргумент типаUnit
, что означает, что есть только один аргумент, который вы можете передать ему: ()
.Поскольку функция является чистой, это означает, что она не может рассматривать что-либо вне своего аргумента, поэтому эта функция также должна возвращать постоянное значение.На самом деле единственная разница между getTimeValue
и getTimeFunc
заключается в том, что вы должны передать getTimeFunc
()
, чтобы получить константу.
Инкапсуляция
То, что существует внешний мир сПонятие «текущего времени», которое вы можете опрашивать и использовать, - это «Контекст», который означает, что любая функция, которая использует это, более не может быть описана полностью в терминах ввода -> вывода.Это описывается как «нечистый».
В DAML все функции чистые, поэтому, если мы хотим обработать «нечистоту», мы должны заключить примесь в чистое значение.В DAML мы выражаем эту инкапсуляцию в виде типа:
encapsulatedImpureValue : m a
, поэтому в нашем случае значение равно Time
:
encapsulatedImpureTimeValue : m Time
Вы можете прочитать это как,инкапсулированное значение типа Time
, которое зависит от контекста m
для оценки.Поскольку мы ничего не упомянули о контексте m
, кроме того, что он существует, этого недостаточно для его реализации.В частности, мы должны также сказать, что контекст должен быть единым с понятием «текущее время», и именно так мы получаем сигнатуру getTime
в стандартной библиотеке DAML:
getTime : (HasTime m) => m Time
Что вы можете прочитать как: инкапсулированное значение времени Time
, которое зависит от контекста m
, которое поддерживает HasTime
(т. Е. Понятие «текущего времени»).
Использование инкапсулированных значений
Теперь мы можем написать:
let now = getTime
и now
будет чистым инкапсулированным значением - что не сразу полезно, так как любая попытка использовать его влюбая функция, ожидающая чистого значения Time
, потерпит неудачу, так как это потребует нарушения инкапсуляции, и DAML строго предписывает нарушения инкапсуляции как ошибки компиляции.
Чтобы использовать инкапсулированное значение, вы должны сначала указать подходящий контекст, изатем запустите значение в этом контексте.DAML предоставляет два контекста, которые поддерживают HasTime
: Update
и Scenario
.Он также предоставляет один способ запуска Scenario
упакованных значений и один способ запуска Update
упакованных значений, а также два способа преобразования Update
значений в Scenario
значений.
Каждое значение сценария верхнего уровня в модуле DAML будет выполняться интерпретатором DAML как тест DAML.
Тело каждого варианта шаблона DAML определено как значение Update
который будет запущен при выполнении выбора.
Вы можете использовать функции submit
и submitMustFail
для получения значения Scenario
, которое при запуске будет запускатьUpdate
значение, разрешенное как назначенное Party
.
Составление инкапсулированных значений
Существует ряд стандартных API, общих для почти всех функциональных языков для составленияинкапсулированные значения в составные значения.Вы услышите о самых известных: "Функтор" и "Монад"Определите функции, которые принимают инкапсулированные значения и функции и комбинируют их различными способами.Инкапсуляция является настолько фундаментальным принципом разработки программного обеспечения, что неудивительно, что большинство языков FP предоставляют синтаксический сахар для упрощения их использования - и DAML ничем не отличается.
Инкапсулированное значение, которое является экземпляром FunctorИнтерфейс поддерживает функцию fmap
, для которой DAML также предоставляет в качестве инфиксного оператора <$>
.
Инкапсулированное значение, являющееся экземпляром интерфейса Monad (называемое Action
в DAML), поддерживает fmap
, pure
и функции bind / flatMap.DAML предоставляет return
в качестве псевдонима для pure
;и оператор >>=
для bind / flatMap.Он также предоставляет do-нотацию как синтаксический сахар для >>=
, поэтому:
do
t <- getTime
a <- useTime t
combineWithTime a t
Создает составное значение Update
, которое (при запуске) запускает getTime
, передает полученное значение в useTime
затем передает оба результата combineWithTime
.Результатом этого do-блока также является инкапсулированное значение Update
, поэтому мы не нарушаем инкапсуляцию, потому что к моменту запуска updateA/B/C
мы предоставили контекст инкапсуляции для включающего составного Update
значения.
Если (как вы делаете в своем примере) мы сделаем так, чтобы do
заблокировал тело выбора, то при выполнении выбора будет запущено составное обновление.В качестве альтернативы, если мы передадим его в submit
, мы можем запустить его как часть сценария.Если вы не сделаете ни одного (что может случиться, если, например, у вас есть два значения Update и вы используете выражение if для выбора между ними), это не окажет заметного эффекта, потому что в DAML все функции чистые.