Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics F#类型约束-类型变量';a已被限制为类型'';b';_Generics_F#_Monads - Fatal编程技术网

Generics F#类型约束-类型变量';a已被限制为类型'';b';

Generics F#类型约束-类型变量';a已被限制为类型'';b';,generics,f#,monads,Generics,F#,Monads,我试图让一个函数工作,它打开一个信封类型,将一个函数应用于内容并返回一个信封类型。有点像煎饼的绑定功能 type Envelope<'a> = { Content : 'a ; Errors : string list } let (!>) f e = let {Content=content:'a; Errors=errors} = e match errors with | [] -> e : Envelope<'a>

我试图让一个函数工作,它打开一个信封类型,将一个函数应用于内容并返回一个信封类型。有点像煎饼的绑定功能

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>

问题是匹配的两种情况都应该返回相同的类型,否则在类型系统中就没有意义了

你需要构造一个新的信封,但我想问题是如果有错误,你不想计算f,所以一种黑客的方法是:

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>
键入信封)f e=
设{Content=Content:'a;Errors=Errors}=e
将错误与
|[]->{Content=Unchecked.defaultof;Errors=e.Errors}:信封
但这不是你想要的,因为你会丢失内容


正确的方法是使用有歧视的联合,而不是记录,但我认为你想要的是在有错误的时候应用补偿函数,所以在这种情况下,你的补偿函数不能是多态的,因此,原始错误消息。

在我看来,您要么试图映射错误,要么在出现错误时获取默认值。这里有几个选项

type Envelope<'a> = { 
    Content : 'a
    Errors : string list
}

/// (unit -> 'a) -> Envelope<'a>  -> 'a
let defaultWith f e =
    match e.Errors with
    | [] -> e.Content 
    | _  -> f()
另一方面,如果有错误,这两种方法可以让您映射整个封套。您可以为我刚才留下的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

//('a->Envelope->Envelope string list->Envelope->Envelope->Envelope谢谢你的评论,我也很担心。可能有什么方法可以“欺骗”编译器,让它认为
'a
被强迫成了
'b
?应该没有理由认为
'a
是与
'b
不同的类型。(因此,强制
e:>envelope为什么要强制?请注意,编译器并没有指出一个技术问题,这是一个逻辑问题。你的函数应该返回苹果,而不是苹果,有时是桔子,这没有任何意义。当你这样说的时候,你是对的,这没有任何意义。我试着看看它们的小部分n常见的是信封。我想没有更多了,必须重写…PS,如果你对C感兴趣的话,我会这样写:用一种答案编辑我的原始问题。将信封包装在DU中似乎可以达到目的…是的,但是当你打开DU时,你将被迫处理不同的类型。这也将限制y您只需要使用补偿一次。我强烈的感觉是,将补偿函数定义为
f:'t->'t
并没有什么错,看起来您想要的是f#
结果
类型(内置于f#自f#4.1以来)。有关更多详细信息,请参阅。在您的情况下,我认为
'TError
将是
字符串列表
@rmunn,它将我的类型从记录更改为du,信封的思想是我将其传递,在我的作文结束时对内容en执行操作使用此信封向浏览器发送正确的响应。只需返回t错误(字符串列表)将删除“知识”我正在做的事情。您是否试图将错误映射到有效值?这是否等同于
选项。defaultWith
。感谢您的消息,这非常有用,但我希望有一个来自
'a->Envelope
的函数。这样,我可以链接转换数据的函数并管理一般错误给我一个你会如何使用它的具体例子。
/// (string list -> string list) -> Envelope<'a> -> Envelope<'a>
let mapErrors f e =  
    match e.Errors with
    | [] ->   e
    | _  -> { e  with Errors = f e.Errors }
/// ('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