0

一段时间以来, F # 支持使用[<ReflectedDefinitionAttribute>]. 懒惰有什么类似的吗?

例如

    member __.Quoted ([<ReflectedDefinitionAttribute>] quotation:Expr<'T>) = ... 
    member __.Thunked ([<LazyAttribute>] thunk:Lazy<'T>) = ... 

我想我可以使用类似的东西

    member __.Quoted ([<ReflectedDefinitionAttribute>] quotation:Expr<'T>) = 
        Lazy (evaluate (<@ fun () -> %quotation @>)) // evaluate using Unquote or similar

但这不会很昂贵吗?

更新

我发现了一个 hack,它不完全是我想要的,但它给出了正确的行为。

type Signal = Signal with
    member __.Return x = x
    member __.Delay (f:unit -> _) = f

let a = Signal { return randint }
let b = Signal { return randint }
let c = Signal { return a() + b() }
4

1 回答 1

3

没有什么比ReflectedDefinition自动将事情变成延迟Lazy<'T>计算的属性更好的了。

你是对的,自动引用参数可以达到这样的效果。您可以对某些有限种类的表达式使用 (very limited)LeafExpressionConverter.EvaluateQuotation来执行此操作,但正如您所指出的,这将是低效的。以下是一个概念证明(但您不能在分支中调用自定义函数,因为它使用 LINQ 表达式):

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers

type A = 
  static member If<'T>(c:bool,
      [<ReflectedDefinition>] t:Expr<'T>,
      [<ReflectedDefinition>] f:Expr<'T>) = 
    if c then LeafExpressionConverter.EvaluateQuotation t :?> 'T
    else LeafExpressionConverter.EvaluateQuotation f :?> 'T

A.If(1 = 2, 0, 1)

在实践中,我认为更合理的方法是只使用内置Lazy<'T>值。F# 有一个(不广为人知的)lazy关键字,它为您提供了更好的语法来创建它们:

let iff c (t:Lazy<_>) (f:Lazy<_>) = 
  if c then t.Value else f.Value

iff (1 = 2) 
  (lazy (printfn "true"; 41)) 
  (lazy (printfn "false"; 42))
于 2021-05-04T10:41:57.043 回答