F# 分配具有选项的记录项会引发编译错误

F# 分配具有选项的记录项会引发编译错误,f#,F#,我对后缀分配的错误感到困惑: { First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) } type String20 = String20 of string type Name = { First:String20 Last:String20 Suffix:String20 option } let tryCreateName (first:s

我对后缀分配的错误感到困惑:

{ First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) }
type String20 = String20 of string

type Name = { First:String20
              Last:String20
              Suffix:String20 option }

let tryCreateName (first:string) (last:string) (suffix:string option) = 

    let isValid = [first; last] |> List.forall (fun x -> x.Length > 2 && x.Length <= 20)

    if isValid then 
        Some{ First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) }
    else None
错误:

{ First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) }
type String20 = String20 of string

type Name = { First:String20
              Last:String20
              Suffix:String20 option }

let tryCreateName (first:string) (last:string) (suffix:string option) = 

    let isValid = [first; last] |> List.forall (fun x -> x.Length > 2 && x.Length <= 20)

    if isValid then 
        Some{ First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) }
    else None
此表达式应具有字符串类型

代码:

{ First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) }
type String20 = String20 of string

type Name = { First:String20
              Last:String20
              Suffix:String20 option }

let tryCreateName (first:string) (last:string) (suffix:string option) = 

    let isValid = [first; last] |> List.forall (fun x -> x.Length > 2 && x.Length <= 20)

    if isValid then 
        Some{ First=String20 first; Last=String20 last; Suffix=Some(String20 suffix) }
    else None
类型String20=字符串的String20
类型名称={First:String20
最后:第20条
后缀:String20选项}
让tryCreateName(第一个:字符串)(最后一个:字符串)(后缀:字符串选项)=

让isValid=[first;last]|>List.forall(fun x->x.Length>2&&x.Length函数的
后缀
参数的类型为
字符串选项
,因此在编写时:

Some(String20 suffix)
实际上,您正在尝试将
string选项
包装到
String20
中。您可能需要以下内容:

suffix |> Option.map String20
这会将字符串包装在
String20
构造函数中的选项内,因此您将得到
String20选项


这并不能验证后缀是否有效(有2到20个字符),但这是另一个问题。

函数的
后缀
参数的类型为
字符串选项
,因此在编写时:

Some(String20 suffix)
实际上,您正在尝试将
string选项
包装到
String20
中。您可能需要以下内容:

suffix |> Option.map String20
这会将字符串包装在
String20
构造函数中的选项内,因此您将得到
String20选项

这不会验证后缀是否有效(有2到20个字符),但这是另一个问题。

这会起作用

if isValid then 
    let first20 = String20(first)
    let last20 = String20(last)
    let suffix20 =
        match suffix with
        | Some(str) -> Some(String20(str))
        | _ -> None
    let (name : Name) = { First= first20; Last= last20; Suffix= suffix20 }
    Some(name)
else None
但您设计输入的方式要求如下:

printfn "%A" (tryCreateName "John" "Smith" (Some("II")))
printfn "%A" (tryCreateName "Jill" "Smith" None)
这并不像托马斯的回答那么优雅,但应该给你更多的细节来仔细考虑。

这会有用的

if isValid then 
    let first20 = String20(first)
    let last20 = String20(last)
    let suffix20 =
        match suffix with
        | Some(str) -> Some(String20(str))
        | _ -> None
    let (name : Name) = { First= first20; Last= last20; Suffix= suffix20 }
    Some(name)
else None
但您设计输入的方式要求如下:

printfn "%A" (tryCreateName "John" "Smith" (Some("II")))
printfn "%A" (tryCreateName "Jill" "Smith" None)

这并不像Tomas的回答那么优雅,但应该给你更多的细节让你仔细思考。

作为旁白,你可能想看一下页面的一半。这将要求你使用元组作为输入,而不是咖喱。然后你就可以摆脱对后缀的一些或没有要求。顺便说一句,你的代码有一个微妙的错误。你没有验证后缀长度::)最好将String20构造函数设置为私有,并使用一个特殊的“智能”构造函数进行验证。这样,您就永远不会意外地拥有无效的String20。不过,这完全是另一个话题!作为旁白,你可能想看看这一页的一半。这将要求您对输入使用元组,而不是咖喱。然后,您可以取消对后缀的部分或全部要求。顺便说一句,您的代码有一个微妙的错误。您没有验证后缀长度。:)最好将String20构造函数设置为私有,并使用一个特殊的“智能”构造函数进行验证。这样,您就永远不会意外地拥有无效的String20。不过,这完全是另一个话题!这可能也会使验证逻辑的实现更加容易!这可能也会使验证逻辑的实现更加容易!