轨道
/
Gleam
Gleam
/
练习
/
专家实验
专家实验

专家实验

学习练习

简介

use 表达式

在 Gleam 中,编写和使用高阶函数很常见,也就是把其他函数作为实参的函数。有时同时使用多个高阶函数,代码会变得难以阅读,出现一层又一层的缩进。

例如,下面这个函数调用了几个返回 Result(Int, Nil) 的函数,并在四个都成功时把它们的值相加。

import gleam/result

pub fn main() -> Result(Int, Nil) {
  result.try(function1(), fn(a) {
    result.try(function2(), fn(b) {
      result.try(function3(), fn(c) {
        result.try(function4(), fn(d) {
          Ok(a + b + c + d)
        })
      })
    })
  })
}

Gleam 的 use 表达式让我们不用缩进就能写出这段代码,通常也更容易阅读。

import gleam/result

pub fn main() -> Result(Int, Nil) {
  use a <- result.try(function1())
  use b <- result.try(function2())
  use c <- result.try(function3())
  use d <- result.try(function4())
  Ok(a + b + c + d)
}

use 表达式会把代码块中随后的所有语句收集起来,作为一个回调函数,作为最后一个实参传给这次函数调用。use 关键字和 <- 符号之间的变量,就是将要传给回调函数的实参的名字。

// This use expression
use a <- function(1, 2)
io.println("Hello!")
a

// Is equivalent to this normal function call
function(1, 2, fn(a) {
  io.println("Hello!")
  a
})

回调函数可以接收任意数量的实参,也可以一个都不接收。

use a, b, c, d <- call_4_function()

use <- call_0_function()

要想创建能用 use 表达式调用的函数,除了把回调函数作为最后一个实参之外,没有其他特殊要求。

pub fn call_twice(function: fn() -> t) -> #(t, t) {
  let first = function()
  let second = function()
  #(first, second)
}

Gleam 的 use 表达式是一个非常强大的功能,可以用于解决很多问题,但用得过多反而会让代码难以阅读。通常更推荐使用普通的函数调用语法,只有当 use 表达式能让代码更易读时才去使用它。

说明

Daphne 一直在开发一个系统,用来运行并记录她的实验结果。有些代码变得有点冗长、重复,所以她请你写一些use表达式来帮忙精简一下。

1. 定义with_retry函数

有时实验会因为一次性的失误而失败,所以如果实验失败了,Daphne 想再重试一次,看看第二次能不能成功。

定义with_retry函数,它接受一个返回结果的函数作为实参。

如果这个函数返回Ok值,那么with_retry应该返回该值。

如果这个函数返回Error值,那么with_retry应该再次调用这个函数,并返回那次调用的结果。

Daphne 会这样使用这个函数:

pub fn main() {
  use <- with_retry
  // Perform the experiment here
}

2. 定义record_timing函数

Daphne 通过在每次实验前后调用一个记录时间的函数,来记录每个实验运行了多久。

定义record_timing函数,它接受两个实参:

  • 一个记录时间的函数,它不接受任何实参,并返回Nil。
  • 一个实验函数,它不接受任何实参,并返回一个结果。

record_timing应该先调用记录时间的函数,然后调用实验函数,接着再次调用记录时间的函数,最后返回实验函数的结果。

Daphne 会这样使用这个函数:

pub fn main() {
  use <- record_timing(time_logger)
  // Perform the experiment here
}

3. 定义run_experiment函数

实验由三个阶段组成:设置、操作和记录。三个阶段都会返回结果,而且每个阶段都需要上一个阶段的成功结果才能运行。

定义run_experiment函数,它接受四个实参:

  • 实验的名称,类型为String。
  • 一个设置函数,它不接受任何实参,并返回一个结果。
  • 一个操作函数,它以设置函数返回的Ok值作为实参,并返回一个结果。
  • 一个记录函数,它以设置函数和操作函数返回的Ok值作为实参,并返回一个结果。

如果这三个函数都成功,那么run_experiment应该返回Ok(#(experiment_name, recording_data))。

如果其中任何一个函数返回Error值,那么run_experiment应该返回该值。

Daphne 会这样使用这个函数:

pub fn main() {
  use setup_data, action_data <- run_experiment("Test 1", setup, action)
  // Record the results here
}
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Gleam Exercism

准备好开始 专家实验 了吗?

注册 Exercism,借助 33 个概念122 个练习 和真人导师指导,学习并掌握 Gleam,全部免费。