首页 > 解决方案 > F# Monad 如何修复数据类型

问题描述

我正在尝试在 F# 中编写 Monad,但无法编译代码,并且出现错误 FS0001 错误:此表达式的类型应为“Result”,但此处的类型为“(Result<'a> -> Result<' b>) -> 结果<'b>'

open System
type Result<'TSuccess> =
     | Success of 'TSuccess
     | Failure

let bind x f = 
    match x with 
    |  Success x -> f (Success x)
    | Failure -> Failure



let stringToInt (s:string) = 
    try
       let result = s |> int
       Success result 
    with 
       |_-> Failure 

let isPositive (i:int)  = 
    if ( i >  0) then  Success i : Result<int>
    else Failure 

let toString (i:int) = 
    try
       let result = i |> string
       Success result
    with
       |_ -> Failure

let bindIsPositive =  bind isPositive : Result<int>

let bindToString = bind toString : Result<string>

let (>>=) x f = bind f x



let strintToIntIsPositiveIntToString s =  stringToInt >>= bindIsPositive >>= bindToString

[<EntryPoint>]
let main argv =
    printfn "10"
    let mys = strintToIntIsPositiveIntToString "9"
    Console.WriteLine mys.ToString
    0 // return an integer exit code 

标签: f#monads

解决方案


首先,你的类型bind不对:

your version : Result<'a> -> (Result<'a> -> Result<'b>) -> Result<'b>
typical type : Result<'a> -> ('a -> Result<'b>) -> Result<'b>

如果您切换参数的顺序以获取以下内容,其余的工作也会容易得多:

bind : ('a -> Result<'b>) -> Result<'a> -> Result<'b>

因此,您可以使用以下内容bind

let bind f x = 
    match x with 
    | Success x -> f x
    | Failure -> Failure

完成此操作后,您可以定义bindIsPositivebindToString。该bind操作现在将一个函数作为第一个参数,所以这是可行的,但您必须删除您的类型注释:

let bindIsPositive =  bind isPositive 
let bindToString = bind toString

组合函数时,您可以使用>>=运算符,也可以使用普通的 F# 管道和bind函数:

let strintToIntIsPositiveIntToString x =  x |> stringToInt |> bindIsPositive |> bindToString
let strintToIntIsPositiveIntToString x =  x >>= stringToInt >>= isPositive >>= toString

推荐阅读