类型导游和花园路径

2021-05-13 05:57:26

“类型有助于您推理效果”,我们宣布。他们这样做!除非他们没有。 “只是遵循类型!”我们坚持。但有时这些类型带你沿着花园道路。

当校验器很开心但行为都错了时,很难找到你犯了错误的转弯。在这篇文章中,我将分享这种现象的真实例子,并提供一些关于如何避免它的提示。

应用类型类提供了将“纯”值升至应用数据类型的功能:

纯粹的:: a - >课程申请(K :: * - > *)。 K a(< *>):: k(a - > b) - > K a - > K B.

假设我们有一个A类型的Value的随机生成器,并希望生成随机应用程序。这个问题的形状是:

如何实现这一点?遵循类型! T有一个申请实例,所以如果我们在f上介绍Functor约束,我们可以写:

有效节奏::(仿函数f,申请t)=> f a - > f(t a)effap = fmap纯

现在我们有一个漂亮的一般函数,运行效果并将结果升级为申请。让我们通过生成Word8的单值列表来测试它:

数据v3 a = v3 a a - 钻孔实例功能Functor v3实例应用V3实例可折叠V3实例遍历V3

λ> effap randomio :: io(v3 word8)v3 186 186 186 186λ> effap randomio :: io(v3 word8)v3 215 215 215

哦亲爱的。我们遵循类型来实现有效图,但实施不正确!而不是运行3次效果以生成3个随机向量组件,而是运行一次效果并使用结果3次。

第一次应该首先使用纯的效果将效果提升到适用类型中,给出类型的值(申请t)=> t(f a)。孔的形状现在是t(f a) - > f(t a)。这正是Sequencea的形状:

有效::(遍历T,申请F,申请T)=> f a - > f(t a)effap = sequencea。纯的

V3是FMAP纯和序列叶的众多类型之一。纯粹的表现不同。其他示例包括加入(,)和代理。

在Purebred中,我们有一个输入验证系统,将输入作为用户类型检查。它将验证工作调度到后台线程,因此UI响应。每次用户编辑输入时,程序都会杀死未完成的验证线程(如果有的话)并产生一个新的验证线程。程序代码(简化本文)是:

dispatchvalidation = do evawn = forkio dovalidation oldid< - getvalidationThread newId< - 也许产卵(killthread $> spawn)oldid _< - setValidationThread(只是NewID)

未完成的验证线程存储在可能的ThreinID中。在程序中的情况下,程序杀死旧线程,会产生一个新的线程并返回新的ThreadID:

除了,它没有。一目了然,我们看到以正确的顺序发生的行动。但有一个错误。输入验证具有意外和非法的结果。例如,有效输入可能(或可能不会)导致显示错误。

Killthread $> spawn = const spawn< $> Killthread - ($>)= const spawn的定义。 Killthread - for(( - >)r)= \ x - > Const Spawn(Killthread X) - (。)= \ x - &gt的定义;产卵 - Const的定义

表达式丢弃了旧的线程,也不会执行KillTread。因此,验证线程野外运行,完成他们的工作以非必要的顺序。

我讨论了两个错误,其中类型检查器是快乐的,代码似乎是一定的合理的。两者都以“型号”(型号“(这里适合的是什么)的实现,这结果是根本错误的。什么策略可以帮助避免这种陷阱?

第一个错误涉及使用错误的抽象;仿函数而不是申请人。努力尝试具有更大多样性实例的通用函数可能有助于更快地发现此错误。在适用权的情况下,不仅仅是测试[],也许和其他“常见的”类型,其中纯构造了“单例”值。使用代理A(具有零值)的测试,加入(,)a(两个值),等等。

至于第二个错误,我的建议在编写有效的代码时,不要试图成为聪明的。应符号和显式绑定很好。使用下划线绑定以忽略值可能会导致比Const和相关功能更具可读代码。如果您有一个具有函数类型的孔,请首先编写lambda,然后逐步工作以完成定义。确保首先是正确的,只有这样整理(如果您愿意)。

在纯种错误的情况下,我们有一个带有TreinID的洞 - > IO TrimeID,并用表达式填充它,巧妙地忽略了ThreadID参数。我们的下一步是,当面对这个孔时,应该是写表达式(\ trainid - > _)。批判性地,这绑定了ThreadID参数,使其难以忽略。

最后的外带是:不要对类型系统的力量沾沾自喜。类型导向的开发确实很精彩而强大,但是让我们诚实地说,在许多情况下,单独推理的推理不会让您一直到正确的解决方案。相反,你可能会在花园路径的尽头找到自己!