F# 风流莺函数
F# Suave warbler function
我已经开始学习 F# 和 Suave
,并且正在阅读 F# Applied 一书。
我正在努力解决的一件事是 warbler
函数。我知道它与延迟执行有关,但我真的不明白为什么以及何时需要它。
显然我们也可以使用 request
函数作为 warbler
的替代方法。
任何人都可以提供更多关于使用这些功能的原因和时间的详细信息。
这三个函数是相关的,因为 request
和 context
是 warbler
的特殊版本。他们都做同样的事情 - 他们检查他们的论点(的某些方面)并返回一个函数以应用于该论点。
请记住,Suave WebPart
的基本“构建块”是一个函数 HttpContext -> Async<HttpContext option>
而不是某个具体对象。这实际上意味着这三个函数允许你检查这个 HttpContext
并基于它组成一个 WebPart
来使用。
warbler
的核心作用非常简单:
let warbler f a = f a a
// ('t -> 't -> 'u) -> 't -> 'u
你给它一个函数 f
和参数 a
。函数 f
查看 a
并返回一个新函数 't -> 'u
然后应用于 a
.
关于 warbler
的事情是它是完全通用的 - 只要类型对齐,您可以在任何使用 context
或 request
的地方使用它,但它不我对 Suave 感兴趣的域一无所知。
这就是为什么它有“说领域语言”的专门版本的原因:
let request apply (a : HttpContext) = apply a.request a
// (HttpRequest -> HttpContext -> 'a) -> HttpContext -> 'a
let context apply (a : HttpContext) = apply a a
// (HttpContext -> HttpContext -> 'a) -> HttpContext -> 'a
请注意,它们与 warbler 具有相同的“形状”- 唯一的区别是 HttpContext
类型是“硬编码”- 使用起来更方便。
另一个答案已经解释了 warbler
函数及其与 context
和 request
函数的关系。我想告诉你什么时候要用这些。
启动 Suave 服务器时,需要为其提供 WebParts
的请求处理管道 - 路由、HTTP 方法和响应生成函数。这意味着当您启动 Web 服务器时,提供给部分应用的 WebPart
函数的所有参数都已经被评估。
想象一个打印当前服务器时间的简约网络应用程序:
let app = GET >=> path "/" >=> OK (string DateTime.Now)
如果您使用此 app
管道启动网络服务器,您将始终看到创建 app
值时生成的相同时间戳,无论您何时发出网络请求检索它.
warbler
函数及其专用版本 context
和 request
不仅可以延迟执行,还可以让 Web 服务器在每次需要结果时调用提供的函数.
在示例场景中,此 app
将提供预期结果:
let app = GET >=> path "/" >=> warbler (fun ctx -> OK (string DateTime.Now))
@adzdavies 的评论显示了一种您不一定需要 warbler
的替代方法。在示例中,如果您使用匿名函数语法而不是部分应用 OK
.
,您还可以推迟参数评估
let app = GET >=> path "/" >=> (fun ctx -> OK (string DateTime.Now) ctx)
我发现之前的解释让我感到困惑。这是我试图澄清的...
warbler
解决了优化的不纯急切求值函数式语言的问题,在这种语言中,部分应用的参数会提前求值并缓存。当这些应用的参数依赖于副作用并且希望每次调用都有新值时,这种缓存会出现问题。例如,以下对当前系统时间的 string
表示的查询将发生并缓存在 g: string -> string
的定义中。因此,对于 g
:
的每个后续调用,它将 return 相同的值
let g = sprintf "%s %s" (string DateTime.Now)
g "a" //"12/09/2020 18:33:32 a"
g "b" //"12/09/2020 18:33:32 b"
但是,warbler
概念对于解决此重新评估问题是不必要的。只需将主题函数简单地包装在一个匿名函数中,然后每次都完全应用主题函数就足够了,如下所示:
let f = (fun x -> sprintf "%s %s" (string DateTime.Now) x)
f "c" //"12/09/2020 18:53:32 c"
f "d" //"12/09/2020 18:53:34 d"
warbler
正在做的是将上述匿名函数用作函数工厂,在调用时生成主题函数。然后用它的第二个参数调用该主题函数。 warbler
使用它的第二个参数来调用工厂函数是偶然的,但它确实存在误导点。可以想象,将参数传递给工厂可以让工厂配置主题函数函数或select替代类型兼容函数到return到warbler
。尽管如此,这并不是 warbler
的目的。
let warbler f x = (f x) x
需要注意的是,要使重新计算生效,f
在调用点必须是匿名函数。因此,warbler
概念似乎不再有任何实用性,这个很酷的名称可能应该被弃用,并允许重新出现一些其他有用的概念。
顺便说一下,我遇到 warbler
是遇到 Giraffe
。
我已经开始学习 F# 和 Suave
,并且正在阅读 F# Applied 一书。
我正在努力解决的一件事是 warbler
函数。我知道它与延迟执行有关,但我真的不明白为什么以及何时需要它。
显然我们也可以使用 request
函数作为 warbler
的替代方法。
任何人都可以提供更多关于使用这些功能的原因和时间的详细信息。
这三个函数是相关的,因为 request
和 context
是 warbler
的特殊版本。他们都做同样的事情 - 他们检查他们的论点(的某些方面)并返回一个函数以应用于该论点。
请记住,Suave WebPart
的基本“构建块”是一个函数 HttpContext -> Async<HttpContext option>
而不是某个具体对象。这实际上意味着这三个函数允许你检查这个 HttpContext
并基于它组成一个 WebPart
来使用。
warbler
的核心作用非常简单:
let warbler f a = f a a
// ('t -> 't -> 'u) -> 't -> 'u
你给它一个函数 f
和参数 a
。函数 f
查看 a
并返回一个新函数 't -> 'u
然后应用于 a
.
关于 warbler
的事情是它是完全通用的 - 只要类型对齐,您可以在任何使用 context
或 request
的地方使用它,但它不我对 Suave 感兴趣的域一无所知。
这就是为什么它有“说领域语言”的专门版本的原因:
let request apply (a : HttpContext) = apply a.request a
// (HttpRequest -> HttpContext -> 'a) -> HttpContext -> 'a
let context apply (a : HttpContext) = apply a a
// (HttpContext -> HttpContext -> 'a) -> HttpContext -> 'a
请注意,它们与 warbler 具有相同的“形状”- 唯一的区别是 HttpContext
类型是“硬编码”- 使用起来更方便。
另一个答案已经解释了 warbler
函数及其与 context
和 request
函数的关系。我想告诉你什么时候要用这些。
启动 Suave 服务器时,需要为其提供 WebParts
的请求处理管道 - 路由、HTTP 方法和响应生成函数。这意味着当您启动 Web 服务器时,提供给部分应用的 WebPart
函数的所有参数都已经被评估。
想象一个打印当前服务器时间的简约网络应用程序:
let app = GET >=> path "/" >=> OK (string DateTime.Now)
如果您使用此 app
管道启动网络服务器,您将始终看到创建 app
值时生成的相同时间戳,无论您何时发出网络请求检索它.
warbler
函数及其专用版本 context
和 request
不仅可以延迟执行,还可以让 Web 服务器在每次需要结果时调用提供的函数.
在示例场景中,此 app
将提供预期结果:
let app = GET >=> path "/" >=> warbler (fun ctx -> OK (string DateTime.Now))
@adzdavies 的评论显示了一种您不一定需要 warbler
的替代方法。在示例中,如果您使用匿名函数语法而不是部分应用 OK
.
let app = GET >=> path "/" >=> (fun ctx -> OK (string DateTime.Now) ctx)
我发现之前的解释让我感到困惑。这是我试图澄清的...
warbler
解决了优化的不纯急切求值函数式语言的问题,在这种语言中,部分应用的参数会提前求值并缓存。当这些应用的参数依赖于副作用并且希望每次调用都有新值时,这种缓存会出现问题。例如,以下对当前系统时间的 string
表示的查询将发生并缓存在 g: string -> string
的定义中。因此,对于 g
:
let g = sprintf "%s %s" (string DateTime.Now)
g "a" //"12/09/2020 18:33:32 a"
g "b" //"12/09/2020 18:33:32 b"
但是,warbler
概念对于解决此重新评估问题是不必要的。只需将主题函数简单地包装在一个匿名函数中,然后每次都完全应用主题函数就足够了,如下所示:
let f = (fun x -> sprintf "%s %s" (string DateTime.Now) x)
f "c" //"12/09/2020 18:53:32 c"
f "d" //"12/09/2020 18:53:34 d"
warbler
正在做的是将上述匿名函数用作函数工厂,在调用时生成主题函数。然后用它的第二个参数调用该主题函数。 warbler
使用它的第二个参数来调用工厂函数是偶然的,但它确实存在误导点。可以想象,将参数传递给工厂可以让工厂配置主题函数函数或select替代类型兼容函数到return到warbler
。尽管如此,这并不是 warbler
的目的。
let warbler f x = (f x) x
需要注意的是,要使重新计算生效,f
在调用点必须是匿名函数。因此,warbler
概念似乎不再有任何实用性,这个很酷的名称可能应该被弃用,并允许重新出现一些其他有用的概念。
顺便说一下,我遇到 warbler
是遇到 Giraffe
。