我在合同选择的assert语句中使用getTime,如下所示:
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”类型的值?什么是“ mo时间”?
答案 0 :(得分:2)
getTime
仅在存在分类帐时间概念的事务中才有意义。 m0
是一个类型变量,它根据您的上下文引用Update
或Scenario
。实际上,这仅意味着您需要将getTime
的结果绑定到do
块内的变量:
do
currentTime <- getTime
assert ( startCoverage > currentTime )
答案 1 :(得分:2)
tldr:,按@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中,所有功能都是纯函数。
纯函数是一个可以完全描述为
作为参数传递的值与作为参数返回的值之间的映射
结果。值是具体的东西,例如时间,整数,文本等,以及列表,
记录,值的变体以及我将要了解的其他一些内容
后来。 getTimeValue
是一个值,因此根据定义它是一个常数,
只是“停止时钟”意义上的“当前时间”。
getTimeFunc
是一个函数,其参数类型为Unit
,其中
表示您可以传递一个参数:()
。因为
函数是纯函数,这意味着它不能考虑其函数之外的任何事物
参数,因此此函数还必须返回一个常数。实际上
getTimeValue
和getTimeFunc
之间的唯一区别是您必须
传递getTimeFunc
()
以获得常数。
存在一个带有“当前时间”概念的外部世界, 可以讯问和使用的是“上下文”,这意味着使用 在输入->输出方面,这不再完全描述。 这被描述为“不纯”。
在DAML中,所有功能都是纯函数,因此,如果我们要处理“杂质”,我们有 将杂质封装成纯净值。在DAML中,我们表达了这一点 封装类型:
encapsulatedImpureValue : m a
所以在我们的例子中,值是Time
值:
encapsulatedImpureTimeValue : m Time
您可以将其读取为Time
类型的封装值,该值取决于
要评估的上下文m
。由于我们还没有提及
上下文m
除了存在之外,还不足以让我们
实施它。具体来说,我们还需要说上下文必须是
一个带有“当前时间”的概念,这就是我们最终得到的
DAML标准库中getTime
的签名:
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
。
几乎所有通用的标准API都有很多 用于将封装的值组成复合词的功能语言 价值观。您将听到最著名的:“ Functor”和“ Monad” 这些定义采用封装值和函数的函数,以及 以各种方式将它们结合起来。封装是这样的基础软件 工程原理,大多数FP不足为奇 语言提供了语法糖,使使用它们变得更容易-DAML是 没什么。
作为Functor接口实例的封装值支持
Party
函数,DAML也为此函数提供了中缀运算符fmap
。
一个封装值,它是Monad接口的一个实例(称为
DAML中的<$>
)支持Action
,fmap
和bind / flatMap函数。
DAML提供pure
作为return
的别名;和pure
运算符
绑定/ flatMap。它还为>>=
提供了do-notation作为语法糖,因此:
>>=
产生一个复合do
t <- getTime
a <- useTime t
combineWithTime a t
值,该值(运行时)运行Update
,
将结果值传递到getTime
,然后将两个结果都传递给
useTime
。此do块的结果也封装了combineWithTime
值,
这样我们就不会破坏封装,因为在运行时
Update
我们已经为封装提供了封装上下文
复合updateA/B/C
值。
如果(如您在示例中所做的那样)我们使此Update
阻塞了
选择,然后执行选择将运行复合更新。
另外,如果将其传递给do
,则可以将其作为
场景。如果两者都不做(例如,如果您有
两个更新值,并使用if表达式在它们之间进行选择),然后
它不会产生可观察的效果,因为在DAML中,所有功能都是纯函数。