Trouble using the getTime function

若如初见. 提交于 2020-01-04 14:18:13

问题


I am using getTime inside an assert statement on a contract choice as follows:

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

It generates an error:

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)

Does getTime not return a value of type 'Time'? what is 'mo Time'?


回答1:


getTime only makes sense as part of a transaction where there is a concept of ledger time. The m0 is a type variable which refers to either an Update or Scenario, depending on your context. In practice, this simply means that you need to bind the result of getTime to a variable inside your do block:

do
  currentTime <- getTime
  assert ( startCoverage > currentTime )



回答2:


tldr: Per @bame, you need to bind the result of getTime in an Update or Scenario do-block. ie.

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

To understand what has happened here we need to start with the type of getTime:

getTime : (HasTime m) => m Time

The type signature of the function you were expecting is one of:

getTimeValue : Time

getTimeFunc : () -> Time

To understand the difference you need to consider the concepts of purity and encapsulation.

Purity

In DAML all functions are pure.

A pure function is a function which can be described completely in terms of a mapping between values passed as arguments, to values returned as a result. Values are concrete things such as Time, Int, Text, etc, and Lists, Records, and Variants of values as well as a few other things I'll get to later. getTimeValue is a value, so it is by definition a constant, which will only be the "current time" in the "stopped clock" sense.

getTimeFunc is a function that takes an argument of type Unit, which means there is exactly one argument you can pass to it: (). Because the function is pure, this means it cannot consider anything outside of its argument, so this function must also return a constant value. In fact the only difference between getTimeValue and getTimeFunc is that you must pass getTimeFunc () to get the constant.

Encapsulation

That there is an outside world with a concept of "current time" that you can interrogate and use is a "Context" that means any function that uses this can no longer be described completely in terms of input -> output. This is described as "impure".

In DAML all functions are pure, so if we want to handle "impurity" we have to encapsulate the impurity in a pure value. In DAML we express this encapsuation as a type thus:

encapsulatedImpureValue : m a

so in our case, where the value is a Time value :

encapsulatedImpureTimeValue : m Time

You can read this as, an encapsulated value of type Time that depends on a context m to evaluate. As we have not mentioned anything about the context m besides that it exists this is not quite enough to allow us to implement it. Specifically, we need to also say that the context has to be one with a concept of "the current time", which is how we end up with the signature of getTime in the DAML standard library:

getTime : (HasTime m) => m Time

Which you can read as: an encapsulated value of time Time that depends on a context m that supports HasTime (ie. the concept of "current time").

Using Encapsulated Values

We can now write:

let now = getTime

and now will be a pure encapsulated value — which is not immediately useful, as any attempt to use it in any function expecting a pure Time value will fail, as that would require breaking the encapsulation, and DAML stricly enforces encapsulation violations as compilation errors.

To use an encapsulated value you must first specify a suitable context, and then run the value within that context. DAML provides two contexts that support HasTime: Update and Scenario. It also provides one way to run a Scenario wrapped values, and one way to run Update wrapped values, and two ways to convert Update values into Scenario values.

  1. Each toplevel Scenario value in a DAML module will be run by the DAML interpreter as a DAML test.

  2. The body of each DAML Template Choice is defined to be an Update value that will be run when the choice is exercised.

  3. You can use the submit, and submitMustFail functions to produce a Scenario value that, when run, will run an Update value authorized as the nominated Party.

Composing Encapsulated Values

There are a number of standard APIs that are common to almost all functional languages for composing encapsulated values into compound values. You will have heard of the most famous: "Functor" and "Monad" These define functions that take encapsulated values and functions and combine them in various ways. Encapsulation is such a fundamental software engineering principle that it shouldn't be surprising that most FP languages provide syntactic sugar to make using these easier — and DAML is no different.

An encapsulated value that is an instance of the Functor interface supports the fmap function, for which DAML also provides as an infix operator <$>.

An encapsulated value that is an instance of the Monad interface (called Action in DAML), supports the fmap, pure, and bind/flatMap functions. DAML provides return as an alias for pure; and the >>= operator for bind/flatMap. It also provides do-notation as syntactic sugar for >>= so:

do
  t <- getTime
  a <- useTime t
  combineWithTime a t

Produces a compound Update value that (when it runs), runs getTime, passes the resulting value to useTime then passes both results to combineWithTime. The result of this do-block is also encapsulated Update value, so we don't break encapsulation because by the time we are running updateA/B/C we have provided the encapsulation context to the enclosing compound Update value.

If (as you do in your example) we make this do block the body of a choice, then exercising the choice will run the compound update. Alternatively, if we pass it to submit we can run it as a part of a scenario. If you do neither (which can happen if, for instance, you have two Update values, and use an if expression to choose between them), then it will have no observable effect, because in DAML all functions are pure.



来源:https://stackoverflow.com/questions/54792482/trouble-using-the-gettime-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!