F# 类型约束 - 类型变量 'a has been constrained to be type ''b'
F# Type Constraint - The type variable 'a has been constrained to be type ''b'
我正在尝试使一个函数正常工作,该函数可以打开信封类型,将函数应用于内容和 returns 信封类型。有点像墨西哥卷饼的绑定功能。
type Envelope<'a> =
{ Content : 'a
; Errors : string list
}
let (!>) f e =
let {Content=content:'a; Errors=errors} = e
match errors with
| [] -> e : Envelope<'a>
| _ -> f content : Envelope<'b>
错误是:
This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type ''b'.
我有一个 "feeling" 为什么它是错误的,有时我返回一个 Envelope<'a>
而其他时候我返回一个 Envelope<'b>
。
我怎样才能让它工作?我试图使它 "work" 就像我将绑定函数一样,例如,选项类型:
let (>>=) f o =
match o with
| Some v -> f v
| None -> None
问题是匹配的两种情况应该return相同的类型,否则在类型系统中没有意义。
您需要构建一个新的信封,但我想问题是如果出现错误您不想计算 f,所以一个 hacky 的方法是:
type Envelope<'a> =
{ Content : 'a
; Errors : string list
}
let (!>) f e =
let {Content=content:'a; Errors=errors} = e
match errors with
| [] -> {Content = Unchecked.defaultof<_>; Errors = e.Errors } : Envelope<'b>
| _ -> f content : Envelope<'b>
但这不是您想要的,因为您会丢失内容。
正确的方法是使用区分联合,而不是记录,但我想你想要的是在出现错误的时候一直应用补偿函数,所以在那种情况下,你的补偿函数不能' t 是多态的,因此是原始错误消息。
在我看来,您要么试图映射错误,要么在出现错误时获取默认值。这里有几个选项
type Envelope<'a> = {
Content : 'a
Errors : string list
}
/// (unit -> 'a) -> Envelope<'a> -> 'a
let defaultWith f e =
match e.Errors with
| [] -> e.Content
| _ -> f()
这个获取值,如果有错误则调用函数获取默认值。相当于Option.defaultWith
。它不 return Envelope
。
下一个让您映射错误,仅当存在错误时:
/// (string list -> string list) -> Envelope<'a> -> Envelope<'a>
let mapErrors f e =
match e.Errors with
| [] -> e
| _ -> { e with Errors = f e.Errors }
另一方面,如果有错误,这两个可以让您映射整个信封。您可以创建同一主题的许多变体,我只留下 2 个作为说明:
/// ('a -> Envelope<'a>) -> Envelope<'a> -> Envelope<'a>
let mapIfErrors f e =
match e.Errors with
| [] -> e
| _ -> f e.Content
/// ('a -> string list -> Envelope<'a>) -> Envelope<'a> -> Envelope<'a>
let mapIfErrors2 f e =
match e.Errors with
| [] -> e
| _ -> f e.Content e.Errors
我正在尝试使一个函数正常工作,该函数可以打开信封类型,将函数应用于内容和 returns 信封类型。有点像墨西哥卷饼的绑定功能。
type Envelope<'a> =
{ Content : 'a
; Errors : string list
}
let (!>) f e =
let {Content=content:'a; Errors=errors} = e
match errors with
| [] -> e : Envelope<'a>
| _ -> f content : Envelope<'b>
错误是:
This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type ''b'.
我有一个 "feeling" 为什么它是错误的,有时我返回一个 Envelope<'a>
而其他时候我返回一个 Envelope<'b>
。
我怎样才能让它工作?我试图使它 "work" 就像我将绑定函数一样,例如,选项类型:
let (>>=) f o =
match o with
| Some v -> f v
| None -> None
问题是匹配的两种情况应该return相同的类型,否则在类型系统中没有意义。
您需要构建一个新的信封,但我想问题是如果出现错误您不想计算 f,所以一个 hacky 的方法是:
type Envelope<'a> =
{ Content : 'a
; Errors : string list
}
let (!>) f e =
let {Content=content:'a; Errors=errors} = e
match errors with
| [] -> {Content = Unchecked.defaultof<_>; Errors = e.Errors } : Envelope<'b>
| _ -> f content : Envelope<'b>
但这不是您想要的,因为您会丢失内容。
正确的方法是使用区分联合,而不是记录,但我想你想要的是在出现错误的时候一直应用补偿函数,所以在那种情况下,你的补偿函数不能' t 是多态的,因此是原始错误消息。
在我看来,您要么试图映射错误,要么在出现错误时获取默认值。这里有几个选项
type Envelope<'a> = {
Content : 'a
Errors : string list
}
/// (unit -> 'a) -> Envelope<'a> -> 'a
let defaultWith f e =
match e.Errors with
| [] -> e.Content
| _ -> f()
这个获取值,如果有错误则调用函数获取默认值。相当于Option.defaultWith
。它不 return Envelope
。
下一个让您映射错误,仅当存在错误时:
/// (string list -> string list) -> Envelope<'a> -> Envelope<'a>
let mapErrors f e =
match e.Errors with
| [] -> e
| _ -> { e with Errors = f e.Errors }
另一方面,如果有错误,这两个可以让您映射整个信封。您可以创建同一主题的许多变体,我只留下 2 个作为说明:
/// ('a -> Envelope<'a>) -> Envelope<'a> -> Envelope<'a>
let mapIfErrors f e =
match e.Errors with
| [] -> e
| _ -> f e.Content
/// ('a -> string list -> Envelope<'a>) -> Envelope<'a> -> Envelope<'a>
let mapIfErrors2 f e =
match e.Errors with
| [] -> e
| _ -> f e.Content e.Errors