【问题标题】:how to properly use Result.bind如何正确使用 Result.bind
【发布时间】:2021-10-24 10:20:55
【问题描述】:

我目前正在尝试在我的 F# 程序中实现一些验证,但我遇到了一些我无法解决的编译时错误。 沸腾了,我正在努力做到这一点

let ifFalseThenError x errorMessage = function 
   | true -> Ok x 
   | false -> Error errorMessage
let val1 (initialeSandssynligheder : float[]) =
       initialeSandssynligheder
       |> Seq.sum
       |> (fun x -> x < 2)
       |> (fun x -> ifFalseThenError initialeSandssynligheder "Some error")

let val2 initialeSandssynligheder = 
    initialeSandssynligheder 
    |> Array.exists ((<) 0.0) 
    |> (fun x -> ifFalseThenError initialeSandssynligheder "SomeOtherError")

let beregnAlleOvergangssandsynligheder (initialeSandssynligheder: float[])  : float[] = 
       let initialeSandssynligheder = [|1.0;1.0;1.0;1.0;1.0|] 
       let initssh = initialeSandssynligheder 
                     |> val1
                     |> Result.bind val2  // Error here
       initssh

所以我的编译器告诉我,我的类型不匹配。我知道,val1 和 val2 都需要一个 float[] 并返回一个 Result ,当我在我的 val2 中进行管道传输时,我需要对此进行补偿,尽管我可以通过使用 Result.bind 来做到这一点.我在误解什么。

我的错误:

Error   FS0001  Type mismatch. Expecting a
    '(bool -> Result<float [],string>) -> 'a'    
but given a
    'Result<'b,'c> -> Result<'d,'c>'    
The type 'bool -> Result<float [],string>' does not match the type 'Result<'a,'b>'... (Path)

因此,当将 Result.bind 语句添加到最后一次验证时,该消息告诉我虽然我正在补偿什么

【问题讨论】:

  • 请发布编译器错误。不止一个吗?如果是这样,第一个错误是哪一个?它告诉你什么?
  • 谢谢,我刚刚添加了编译器错误,据我了解,它仍然期待抱怨 val2 没有将 作为输入
  • 这不是唯一的编译器错误,是吗?
  • 不正确,但如果我解决了这个问题,我想我可以设法解决其他问题。同一行也给了我这些错误: 严重性代码描述项目文件行抑制状态错误 FS0001 类型不匹配。期望一个 '(bool -> Result) -> 'a' 但给定一个 'Result -> Result' 类型 'bool - > Result' 与类型 'Result' 不匹配(路径)
  • 和严重性代码描述项目文件行抑制状态错误 FS0001 类型不匹配。期望一个 'float [] -> Result' 但给定一个 'float [] -> bool -> Result' 类型 'Result'不匹配类型 'bool -> Result' (path)

标签: functional-programming f#


【解决方案1】:

您对如何使用 Result.bind 的直觉是正确的。但是,您的代码中存在许多错误:

  1. 函数 ifFalseThenError 接受一个布尔值,你不是 路过,在两个val1,val2中。

  2. 在 val1 中,您需要使用浮点值,例如2.0 而不是 int 2。

这里改正了

let ifFalseThenError x errorMessage = function 
   | true -> Ok x 
   | false -> Error errorMessage
let val1 (initialeSandssynligheder : float[]) =
       initialeSandssynligheder
       |> Seq.sum
       |> (fun x -> x < 2.0)
       |> (fun x -> ifFalseThenError initialeSandssynligheder "Some error" x)

let val2 initialeSandssynligheder = 
    initialeSandssynligheder 
    |> Array.exists ((<) 0.0) 
    |> (fun x -> ifFalseThenError initialeSandssynligheder "SomeOtherError" x)

let beregnAlleOvergangssandsynligheder (initialeSandssynligheder: float[])  = 
       let initialeSandssynligheder = [|1.0;1.0;1.0;1.0;1.0|] 


       let initssh = initialeSandssynligheder 
                     |> val1 
                     |> Result.bind val2
       initssh

ps。解决这些问题的一个好方法是为所有函数和参数添加类型注释。

【讨论】:

    【解决方案2】:

    如 cmets 所述,存在多个编译错误:

    1. 数值数据类型不正确
    2. 函数缺少参数
    3. beregnAlleOvergangssandsynligheder 中的返回类型提示错误

    以下版本通过描述更改位置的 cmets 解决了这些编译错误:

    let ifFalseThenError x errorMessage =
      function
      | true -> Ok x
      | false -> Error errorMessage
    
    let val1 (initialeSandssynligheder: float array) =
      initialeSandssynligheder
      |> Seq.sum
      |> (fun x -> x < 2.0) // changed to float
      |> (fun x -> ifFalseThenError initialeSandssynligheder "Some error" x) // include x arg
    
    let val2 initialeSandssynligheder =
      initialeSandssynligheder
      |> Array.exists ((<) 0.0)
      |> (fun x -> ifFalseThenError initialeSandssynligheder "SomeOtherError" x) // include x arg
    
    let beregnAlleOvergangssandsynligheder (initialeSandssynligheder: float array) : Result<float array, string> = // Mixing list/array, hint return result
      let initssh =
        initialeSandssynligheder
        |> val1
        |> Result.bind val2 // Error here
    
      initssh
    
    beregnAlleOvergangssandsynligheder [| 1.0; 1.0; 1.0; 1.0; 1.0 |] // Error because sum > 2
    beregnAlleOvergangssandsynligheder [| -1.0 |] // Error because of negative value
    beregnAlleOvergangssandsynligheder [| 1.0 |] // Ok
    

    我还会查看 array/list/seq 的用法,例如您正在使用数组,但我在这里没有看到任何特定的需求,也许 seq 就足够了吗?尝试选择你需要的那个。

    【讨论】:

    • 我能问两个后续问题吗? 1. 您将 beregnAlleOvergangssandsynligheder 的输入从 float[] 更改为 float 数组)这是为什么? 2. 如果我稍后在函数 beregnAlleOvergangssandsynligheder 中想要获取 initssh 的元素,你会怎么做。假设我想要这样一行:let plusone = initssh.[0] +1
    • 没问题! float[]float array 是同一个东西,你可以使用任何你喜欢的,但我个人通常使用 float array 以免将其与空列表混淆:let x = []。如果您希望能够像示例中那样通过索引访问它,那么数组可能就是您想要的。
    猜你喜欢
    • 2020-12-04
    • 2012-07-12
    • 2013-01-21
    • 2011-12-22
    • 2020-10-14
    • 2015-12-10
    • 2021-01-15
    • 2018-01-31
    • 2011-11-04
    相关资源
    最近更新 更多