f# - 有没有办法让这种延续传递与 codata 示例在 F# 中工作?

标签 f# continuation-passing

type Interpreter<'a> =
| RegularInterpreter of (int -> 'a)
| StringInterpreter of (string -> 'a)

let add<'a> (x: 'a) (y: 'a) (in_: Interpreter<'a>): 'a = 
    match in_ with
    | RegularInterpreter r -> 
        x+y |> r
    | StringInterpreter r -> 
        sprintf "(%s + %s)" x y |> r

无法解析的错误信息'a在编译时对我来说很清楚。我猜测是否可以使上述工作的问题的答案是否定的,没有直接将函数添加到数据类型中。但那我不妨使用一个接口(interface),或者完全摆脱泛型参数。

编辑:马克的回复确实符合我的要求,但让我扩展这个问题,因为我没有充分解释它。我想要做的是用上面的技术做的是模仿在这个 post 中所做的事情。 .这样做的动机是避免内联函数,因为它们的可组合性很差——如果没有专门的通用参数,它们就不能作为 lambdas 传递。

我希望我可以通过将带有通用参数的联合类型传递给闭包来解决它,但是......
type Interpreter<'a> =
| RegularInterpreter of (int -> 'a)
| StringInterpreter of (string -> 'a)

let val_ x in_ =
    match in_ with
    | RegularInterpreter r -> r x
    | StringInterpreter r -> r (string x)

let inline add x y in_ = 
    match in_ with
    | RegularInterpreter r -> 
        x in_ + y in_ |> r
    | StringInterpreter r -> 
        sprintf "(%A + %A)" (x in_) (y in_) |> r

let inline mult x y in_ = 
    match in_ with
    | RegularInterpreter r -> 
        x in_ * y in_ |> r
    | StringInterpreter r -> 
        sprintf "(%A * %A)" (x in_) (y in_) |> r

let inline r2 in_ = add (val_ 1) (val_ 3) in_

r2 (RegularInterpreter id)
r2 (StringInterpreter id) // Type error.

最后一行给出了一个类型错误。有没有解决的办法?尽管由于它们对可组合性的限制,我更希望函数不要被内联。

最佳答案

删除类型注释:

let inline add x y in_ = 
    match in_ with
    | RegularInterpreter r -> 
        x + y |> r
    | StringInterpreter r -> 
        sprintf "(%A + %A)" x y |> r

您还需要进行一些其他更改,我也在上面合并了这些更改:
  • 更改与 sprintf 一起使用的格式说明符更通用的东西。当您使用 %s ,您是说该占位符的参数必须是字符串,因此编译器会推断出 xy成为 string值(value)观。
  • 添加 inline关键词。

  • 通过这些更改,add 的推断类型就是现在:
    x: ^a -> y: ^b -> in_:Interpreter<'c> -> 'c
        when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b -> int)
    

    您会注意到它适用于 + 的任何类型。定义为将输入参数转换为 int .在实践中,这可能只意味着 int本身,除非您定义自定义运算符。

    FSI 烟雾测试:
    > add 3 2 (RegularInterpreter id);;
    val it : int = 5
    > add 2 3 (StringInterpreter (fun _ -> 42));;
    val it : int = 42
    

    关于f# - 有没有办法让这种延续传递与 codata 示例在 F# 中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41322308/

    相关文章:

    f# - F# 中的 ToString() 覆盖不适用于包含另一种类型的类型

    f# - 为什么 Seq.groupBy 不能像我认为的那样与列表一起工作? (F#)

    scala - Scala 中的延续传递风格

    haskell - 有没有办法像 withCString 这样链接函数?

    haskell - curry 语言的 CPS

    c# - 您可以在一个项目中混合使用 .net 语言吗?

    generics - F#:尝试通过界面复制和更新记录时出错

    regex - 使用 Regex 从文件中删除注释

    haskell - 用 CPS 编写的函数如何使许多事情变得明确?

    functional-programming - 延续传球风格与单子(monad)