我已经开始学习 F#,Suave
并且正在阅读F# Applied书。
我正在努力解决的一件事是warbler
功能。我知道这与推迟执行有关,但我真的不明白为什么以及何时需要。
显然我们也可以使用该request
函数作为warbler
.
谁能提供有关使用这些功能的原因和时间的更多详细信息。
另一个答案已经解释了warbler
函数及其context
与request
函数的关系。我想说明你什么时候想使用这些。
当您启动一个 Suave 服务器时,您需要为其提供请求处理管道WebParts
- 路由、HTTP 方法和响应生成功能。这意味着在您启动 Web 服务器时,WebPart
已对提供给部分应用函数的所有参数进行了评估。
想象一个打印当前服务器时间的简约 Web 应用程序:
let app = GET >=> path "/" >=> OK (string DateTime.Now)
如果您使用此app
管道启动 Web 服务器,您将始终看到app
创建值时生成的相同时间戳,无论您何时发出 Web 请求检索它。
该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)
这三个函数在某种意义上是相关的,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
请注意,它们具有与莺相同的“形状”——唯一的区别是HttpContext
类型是“硬编码”的——使其使用起来更方便。
我发现先前的解释令人困惑(对我来说)。这是我试图澄清...
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
的,但它确实存在一个误导点。可以想象,将参数传递给工厂可以允许工厂配置主题函数函数或选择替代类型兼容函数返回到warbler
. 尽管如此,这不是warbler
目的。
let warbler f x = (f x) x
应该注意的是,要使重新评估起作用,f
, 必须是调用点的匿名函数。因此,该概念似乎不再有任何实用性,warbler
并且很酷的名称可能应该被弃用,并允许重新出现以用于其他一些有用的概念。
顺便说一句,我遇到的warbler
是 with Giraffe
。