这个问题最近再次出现在FPish 上。似乎有一个不需要大量重构的简单解决方案。但它需要一个辅助功能:
module Sitelet =
let Filter (ok: 'T -> bool) (sitelet: Sitelet<'T>) =
let route req =
match sitelet.Router.Route(req) with
| Some x when ok x -> Some x
| _ -> None
let link action =
if ok action then
sitelet.Router.Link(action)
else None
{ sitelet with Router = Router.New route link }
假设您有一个包含多个案例的 Action 类型,其中一些是您想要保护的,而一些是公开的:
type Action =
| Pub ..
| Priv ..
过滤允许您在完整类型上使用方便的Infer 组合子,然后安全地将受保护部分和公共部分相加。由于总和的站点是从左到右尝试的,因此保护仅适用于需要的地方:
let s1 =
Sitelet.Infer ..
|> Sitelet.Protect
|> Sitelet.Filter (function Priv _ -> true | _ -> false)
let s2 = Sitelet.Infer ..
Sitelet.Sum [s1; s2]
如果不进行过滤,受保护的站点将捕获所有请求。可能还有其他解决方案,包括重构您的 Action 类型并将其拆分为多个子类型,或者在不使用 Infer 的情况下手动编写站点。