Проблема с использованием функции getTime
Я использую getTime внутри утверждения assert для выбора контракта следующим образом:
Add_Car : CarId
with
startCoverage: Time
do
-- Check for a legal start date
assert (
startCoverage > getTime
)
create this with datetime_vehicle_added = startCoverage, covered=True
Это генерирует ошибку:
error:
* Couldn't match expected type `Time' with actual type `m0 Time'
* In the second argument of `(>)', namely `getTime'
In the first argument of `assert', namely
`(startCoverage > getTime)'
In a stmt of a 'do' block: assert (startCoverage > getTime)
GetTime не возвращает значение типа 'Time'? что такое мо время?
2 ответа
tldr: Per @bame, вам нужно связать результат getTime
в Update
или же Scenario
делать-блок. то есть.
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, общих для почти всех функциональных языков для объединения инкапсулированных значений в составные значения. Вы услышали о самых известных: "Functor" и "Monad". Они определяют функции, которые принимают инкапсулированные значения и функции и комбинируют их различными способами. Инкапсуляция является настолько фундаментальным принципом разработки программного обеспечения, что неудивительно, что большинство языков FP предоставляют синтаксический сахар, облегчающий использование этих функций - и DAML ничем не отличается.
Инкапсулированное значение, являющееся экземпляром интерфейса Functor, поддерживает fmap
функция, для которой DAML также предоставляет инфиксный оператор <$>
,
Инкапсулированное значение, которое является экземпляром интерфейса Monad (называетсяAction
в DAML), поддерживает fmap
, pure
и функции bind/flatMap. DAML обеспечивает return
как псевдоним для pure
; и >>=
оператор для привязки / flatMap. Он также обеспечивает запись в качестве синтаксического сахара для >>=
так:
do
t <- getTime
a <- useTime t
combineWithTime a t
Производит соединение Update
значение, которое (когда он работает), работает getTime
, передает полученное значение useTime
затем передает оба результатаcombineWithTime
, Результат этого do-блока также инкапсулирован Update
значение, поэтому мы не нарушаем инкапсуляцию, потому что к тому времени, когда мы работаемupdateA/B/C
мы предоставили контекст инкапсуляции для вмещающего соединения Update
значение.
Если (как вы делаете в своем примере) мы делаем это do
заблокируйте тело выбора, затем выполнение выбора запустит составное обновление. В качестве альтернативы, если мы передадим его submit
мы можем запустить его как часть сценария. Если вы не сделаете ни одного (что может произойти, если, например, у вас есть два значения Update и вы используете выражение if для выбора между ними), то это не будет иметь заметного эффекта, потому что в DAML все функции являются чистыми.
getTime
имеет смысл только как часть транзакции, где существует концепция времени бухгалтерской книги. m0
переменная типа, которая относится либо к Update
или же Scenario
в зависимости от вашего контекста. На практике это просто означает, что вам нужно связать результат getTime
к переменной внутри вашего do
блок:
do
currentTime <- getTime
assert ( startCoverage > currentTime )