Проблема с использованием функции 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 ценности.

  1. Каждое значение сценария верхнего уровня в модуле DAML будет запускаться интерпретатором DAML в качестве теста DAML.

  2. Тело каждого варианта шаблона DAML определяется как Update значение, которое будет использоваться при выборе.

  3. Вы можете использовать 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 )
Другие вопросы по тегам