【问题标题】:Why does this F# quotation fail at run-time?为什么这个 F# 引用在运行时失败?
【发布时间】:2021-05-07 02:38:55
【问题描述】:

我试图理解为什么这个 F# 脚本在运行时会失败。

#r "nuget: FsToolkit.ErrorHandling, 2.2.0"

open System
open FsToolkit.ErrorHandling

<@@ async {
        return!
          asyncResult {
            return! (Result.Ok true)
          }
} @@>

错误:

$ dotnet fsi ./Quotations.fsx

System.InvalidOperationException: Could not bind function AsyncResultBuilder.Source in type FsToolkit.ErrorHandling.AsyncResultCEExtensions
   at Microsoft.FSharp.Quotations.PatternsModule.fail@1118[a](Type ty, String nm, Unit unitVar0) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1118
   at Microsoft.FSharp.Quotations.PatternsModule.bindModuleFunctionWithCallSiteArgs$cont@1110(Type ty, String nm, Type[] argTypes, Type[] tyArgs, Unit unitVar) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1169
   at Microsoft.FSharp.Quotations.PatternsModule.bindModuleFunctionWithCallSiteArgs(Type ty, String nm, FSharpList`1 argTypes, FSharpList`1 tyArgs) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1105
   at Microsoft.FSharp.Quotations.PatternsModule.u_ModuleDefn@1572-1.Invoke(FSharpList`1 argTypes, FSharpList`1 tyargs) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1576
   at Microsoft.FSharp.Quotations.PatternsModule.u_constSpec@1636.Invoke(FSharpList`1 argTypes, FSharpList`1 tyargs) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1636
   at Microsoft.FSharp.Quotations.PatternsModule.u_Expr@1492.Invoke(BindingEnv env) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1501
   at Microsoft.FSharp.Primitives.Basics.List.mapToFreshConsTail[a,b](FSharpList`1 cons, FSharpFunc`2 f, FSharpList`1 x) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 239
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 247
   at Microsoft.FSharp.Quotations.PatternsModule.u_Expr@1492.Invoke(BindingEnv env) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1493
   at Microsoft.FSharp.Quotations.PatternsModule.u_Expr@1508-2.Invoke(BindingEnv env) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\quotations.fs:line 1508
   at Microsoft.FSharp.Primitives.Basics.List.mapToFreshConsTail[a,b](FSharpList`1 cons, FSharpFunc`2 f, FSharpList`1 x) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 239
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 247
...

这是 F# 引用的问题吗?还是FsToolkit.ErrorHandling 包?

请解释错误信息及其发生原因。

【问题讨论】:

    标签: f# quotations


    【解决方案1】:

    正如上面的答案所述,它可能是由于引号中的过载分辨率而发生的。但是您可以通过将 builder 包装在一个函数中来解决这个问题,然后将其传递给一个引号:

    let returnResult =
      asyncResult {
        return! (Result.Ok true)
      }
          
    let quotation =
      <@@
        async {
          return! returnResult
        }
      @@>
      
    ...
    

    这里returnResult 将是ValueOp 内部的ValueWithName 返回returnResult FSharpFunc。

    【讨论】:

      【解决方案2】:

      我认为简短的答案是两者的结合。以下是我能够确定的:

      • F# 编译器将您的asyncResult 表达式脱糖为对AsyncResultCEExtensions.Source 的调用。见解释here和源代码here。
      • Source 方法有几种不同的重载,所以引用机制有一些复杂的逻辑来试图找出选择哪一个。见源代码here。
      • 很遗憾,引用机制无法确定编译器所考虑的Source 方法,因此它失败并显示您粘贴的错误消息:Could not bind function AsyncResultBuilder.Source in type FsToolkit.ErrorHandling.AsyncResultCEExtensions。

      人们可能会认为这是引用机制中的错误,因为它无法理解编译器的意图。但是,我不确定 F# 是否保证每个可能的合法表达式都是可引用的(因此您遇到了半友好的错误消息)。对 F# 编译器和核心库内部有更多了解的人可能会更加了解。

      【讨论】:

        【解决方案3】:

        这对我有用(注意我使用的是return 而不是return!。我猜类型推断需要更多信息,但我不会进一步调查。

        <@@ async {
            return!
              asyncResult {
                return (Result.Ok true)
              }
        } @@>
        

        更新

        经过进一步调查,似乎可能存在错误。我开了一个新问题System.InvalidOperationException - Could not bind function *** in type

        问题似乎是使用组合的计算表达式库 -

        • 将构建器重载划分为单独的模块
        • 重载源成员(如其他答案中所述)
        • 使用弱类型的Result(整体需要填充)
        • 其他类型不正确的 Source 成员重载,即 Source (s:#seq<_>)
        • 引用内的评估

        其中之一的任何更改都可以解决问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-21
          • 2020-09-13
          • 2012-03-14
          • 1970-01-01
          相关资源
          最近更新 更多