问题
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.
Each toplevel Scenario value in a DAML module will be run by the DAML interpreter as a DAML test.
The body of each DAML Template Choice is defined to be an
Update
value that will be run when the choice is exercised.You can use the
submit
, andsubmitMustFail
functions to produce aScenario
value that, when run, will run anUpdate
value authorized as the nominatedParty
.
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