编译驱动学习

编译驱动学习

原文:https://medium.com/hackernoon/compile-driven-learning-3264034ca266

想象一下。你在你的宠物项目上取得了惊人的进展。您需要再添加一个组件来整合所有内容。你引入了一个外部库来帮助这个组件,而你…却被卡住了。你想知道你应该如何开始。你看一下图书馆的文档。不是特别有帮助。

虽然 Haskell 库的文档并不总是很棒,但也有可取之处。正如我们之前所探讨的,Haskell 是严格类型化的。一般来说,当它编译时,它按照我们期望的方式工作。至少这在 Haskell 中比其他语言更常见。对于学习新的库来说,这可能是一把双刃剑。

一方面,如果你能为函数拼凑出正确的类型,你就成功了。但是,如果对库中的类型不太了解,就很难知道从何下手。如果你不知道如何构造正确类型的东西,你会怎么做?你可以试着写很多代码,但是你会得到大量的错误信息。因为你不熟悉这些类型,所以它们很难理解。

在这篇文章中,我将分享我解决这个学习问题的方法。我称之为“编译驱动学习”。要学习一个新的库或系统,应该从编写尽可能少的代码开始,这样代码才能继续编译。它与测试驱动开发的思想有着错综复杂的联系。我们将在下周的文章中更详细地讨论这个想法,但这里是 10000 英尺。概述。

测试驱动开发

测试驱动开发是一种软件开发的范例,在这种情况下,你在编写源代码之前先编写测试。您考虑您希望代码具有的效果,以及公开的函数应该是什么。然后编写测试,建立对公开功能的期望。一旦你对测试的范围感到满意,你就只需要为一个特性编写源代码。

一旦你这样做了,测试结果驱动开发。您不必花费太多时间来确定您应该实现哪段代码。你找到第一个失败的测试用例,让它通过,清洗并重复。您希望编写尽可能少的代码来通过测试。显然,你不应该只是硬编码函数定义来适应测试。你的测试用例应该足够健壮,这是不可能的。

现在,如果你试图写尽可能少的代码来通过测试,你可能会得到杂乱无章的代码。这可不好。TDD 中解决这个问题的主要思想是红绿重构循环。首先你写测试,失败(红色)。然后你让测试通过(绿色)。然后你重构你的代码,使它符合你正在使用的任何风格标准(重构)。当你完成了这个,你就可以进入下一个功能了。

编译驱动学习

TDD 很棒,但是我们不一定能把它应用到学习一个新的库上。如果你不知道类型,你就不能写出好的测试。所以你可以用这个过程来代替。在某种程度上,我们使用类型系统和编译器来测试我们对代码的理解。我们可以使用这些知识来尽可能地保持代码编译,以实现两个目标:

  1. 推动我们的发展,并准确了解我们下一步打算实施什么。
  2. 避免令人沮丧的“错误之山”效应。

该方法如下所示:

  1. 定义您正在实现的函数,然后将其删除为undefined。(您的代码应该仍然可以编译。)
  2. 在定义函数时尽可能取得最小的进展,这样代码仍然可以编译。
  3. 确定下一段要写的代码,是需要填充的undefined值,还是对象的构造函数的存根部分。
  4. 重复 2–3。

注意,在这个过程的每一步结束时,我们仍然应该有编译代码。这里的undefined值是一个很好的工具。它是 Haskell 中的一个值,可以采用任何类型,所以你可以用它来清除任何函数或值。关键是能够看到实现的下一层。

实践中的 CDL

这是我的副业之一“一周应用”中的一个例子。首先我定义了一个我想写的函数:

swiftFileFromView :: OWAAppInfo -> OWAView -> SwiftFile
swiftFileFromView = undefined

该函数表示,我们希望能够获取一个关于 Swift 应用程序的“应用程序信息”对象以及一个视图对象,并为视图生成一个 Swift 文件。现在我们必须确定下一步。我们希望我们的代码在编译的同时仍然朝着解决问题的方向前进。SwiftFile类型是围绕FileSection项目列表的包装器。所以我们能够做到这一点:

swiftFileFromView :: OWAAppInfo -> OWAView -> SwiftFile
swiftFileFromView _ _ = SwiftFile []

这还编译!诚然,相当不完整!但是我们在正确的方向上迈出了微小的一步

下一步,我们必须确定哪些FileSection对象进入列表。在这种情况下,我们需要三个不同的部分。首先,我们在顶部有评论部分。其次,我们有一个“进口”部分。然后我们有主要的实现部分。因此,我们可以将这些表达式放在列表中,然后在下面将其删除:

swiftFileFromView :: OWAAppInfo -> OWAView -> SwiftFile
swiftFileFromView _ _ = SwiftFile [commentSection, importsSection, classSection]
  where
    commentSection = undefined
    importsSection = undefined
    classSection = undefined

这段代码仍然可以编译。现在我们可以一个接一个地填写部分,而不是一次写完所有的代码。每一个都有自己的组成部分,我们将进一步分解。

利用我们对FileSection类型的了解,我们可以使用BlockCommentSection构造函数。这只需要一个字符串列表。同样,我们将为导入部分使用ImportsSection构造函数。它也需要一个列表。所以我们可以这样进步:

swiftFileFromView :: OWAAppInfo -> OWAView -> SwiftFile
swiftFileFromView _ _ = SwiftFile [commentSection, importsSection, classSection]
  where
    commentSection = BlockCommentSection []
    importsSection = ImportsSection []
    classSection = undefined

所以再一次,我们的代码仍然编译,我们取得了小的进步。现在,我们将确定注释部分需要哪些字符串,并添加它们。然后我们可以为导入部分添加Import对象。如果我们搞砸了,我们将会看到一条错误消息,并且我们将会确切地知道问题在哪里。这有助于更快的开发过程。

摘要

我们讨论了这种学习新库的方法,但它对正常开发也很有帮助!避免一头扎进去写几百行代码的诱惑!处理几十条错误信息你会后悔的!稳扎稳打才能赢得这场比赛。如果您将工作一部分一部分地分解,并使用编译器来检查您的工作,您将会更快地完成工作。

如果你想尝试实现编译驱动学习,你应该看看我们免费的回收工作簿!它有 10 个练习题,以undefined开头。你可以试着一步一步地实现它们,看看你是否能通过测试!

如果您以前从未编写过任何 Haskell,并且想要尝试一下,您应该阅读我们的入门清单。它会告诉你关于写 Haskell 的第一行你需要知道的一切!

最后,下周我们将更深入地讨论测试驱动开发,敬请关注。我们将通过使用测试用例,而不仅仅是看我们的代码是否编译,来看看我们如何能达到类似于 CDL 的效果。

黑客中午是黑客如何开始他们的下午。我们是 AMI 家庭的一员。我们现在接受投稿并乐意讨论广告&赞助机会。

要了解更多信息,请阅读我们的“关于”页面 , 喜欢/在脸书给我们发消息,或者简单地,发推文/DM @HackerNoon。

如果你喜欢这个故事,我们推荐你阅读我们的最新科技故事趋势科技故事。直到下一次,不要把世界的现实想当然!


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除