tldr: 根据@bame,您需要将getTime 的结果绑定到Update
或Scenario do-block。即。
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 中,所有函数都是纯函数。
纯函数是可以完全描述为的函数
作为参数传递的值与作为 a 返回的值之间的映射
结果。值是具体的东西,例如时间、整数、文本等,以及列表,
记录、值的变体以及我将要了解的其他一些内容
之后。 getTimeValue 是一个值,所以根据定义它是一个常量,它
只会是“停止时钟”意义上的“当前时间”。
getTimeFunc 是一个接受Unit 类型参数的函数,它
意味着只有一个参数可以传递给它:()。因为
函数是纯的,这意味着它不能考虑它之外的任何东西
参数,所以这个函数也必须返回一个常量值。事实上
getTimeValue 和 getTimeFunc 之间的唯一区别是您必须
通过getTimeFunc() 获取常量。
封装
存在一个你认为有“当前时间”概念的外部世界
can interrogate and use 是一个“上下文”,表示使用的任何函数
这不能再完全用输入 -> 输出来描述。
这被描述为“不纯”。
在 DAML 中所有函数都是纯函数,所以如果我们想处理“杂质”,我们有
将杂质封装在纯值中。在 DAML 中,我们表达了这一点
封装为一种类型:
encapsulatedImpureValue : m a
所以在我们的例子中,值是Time 值:
encapsulatedImpureTimeValue : m Time
您可以将其解读为 Time 类型的封装值,取决于
要评估的上下文m。因为我们没有提到任何关于
上下文m 除了它存在之外,这还不足以让我们
实施它。具体来说,我们还需要说上下文必须是
一个具有“当前时间”概念的人,这就是我们最终得到的
DAML 标准库中getTime 的签名:
getTime : (HasTime m) => m Time
您可以将其解读为:时间Time 的封装值,取决于
支持HasTime 的上下文m(即“当前时间”的概念)。
使用封装值
我们现在可以写:
let now = getTime
和 now 将是一个纯 封装 值 - 这不是立即
有用,因为任何尝试在任何期望纯 Time 的函数中使用它
value 将失败,因为这需要破坏封装和 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 的别名;和 >>= 运算符
绑定/平面图。它还为 >>= 提供了 do-notation 作为语法糖,所以:
do
t <- getTime
a <- useTime t
combineWithTime a t
产生一个复合 Update 值,(当它运行时)运行 getTime,
将结果值传递给 useTime 然后将两个结果传递给
combineWithTime。这个do-block的结果也封装了Update值,
所以我们不会破坏封装,因为当我们运行时
updateA/B/C 我们已经为封装提供了封装上下文
复合Update值。
如果(就像您在示例中所做的那样)我们将 do 设置为块
选择,然后执行选择将运行复合更新。
或者,如果我们将它传递给submit,我们可以将它作为
设想。如果您都不做(例如,如果您有
两个更新值,并使用 if 表达式在它们之间进行选择),然后
它不会产生明显的影响,因为在 DAML 中所有函数都是纯函数。