OCaml 流水线和类型构造函数参数
OCaml pipelining and type constructor arguments
学习 OCaml,想知道为什么编译器认为我向单参数类型构造函数提供零参数。
这个 OCaml:
open Core
module Json = Yojson.Safe.Util
type ticker = Ticker of string
let ticker_of_yojson s =
s |> Json.to_string |> Ticker |> Result.Ok
产生此错误:
The constructor Ticker expects 1 argument(s)
but is applied here to 0 argument(s).
如果我把它改成这样,用 lambdas 包装构造函数调用,
let ticker_of_yojson s =
s |> Json.to_string |> (fun x -> Ticker x) |> (fun x -> Result.Ok x)
它编译。如果我只将 Ticker
构造函数调用包装在 lambda 中,我会得到与 Result.Ok
.
相同的零参数错误
编译器在这里缺少什么,用 lambda 表达式替换可以解决?是否还有其他我可以添加的东西,以便没有 lambda 的原始版本可以工作?
我看到了另一个 SO post,这似乎是一个类似的问题,但我无法将两种情况联系起来:ocaml type constructor arguments
感谢您的宝贵时间 - 任何帮助表示感谢。
OCaml 构造函数不是函数,语言就是这样工作的。从语法上讲,一元构造函数后面需要一个表达式。所以你不能把一个构造函数本身当作一个函数来使用,你需要按照你说的那样把它包装在一个lambda中。
二元(或三元等)构造函数需要在其后加括号的逗号分隔表达式列表。所以你也不能在 OCaml 中部分应用构造函数。
其他语言(特别是 Haskell)将构造函数视为任何其他(柯里化)函数,并且效果非常好。但此时更改 OCaml 可能为时已晚。
Ticker 是一个构造函数,通常用于定义创建特定类型值的方法。游览 Variants in OCaml.
如果我们看一下 Ticker
的定义
# type ticker = Ticker of string;;
type ticker = Ticker of string
本质上,我们正在定义一个名为 ticker 的类型,其值可以使用右侧的构造函数 Ticker 创建,它采用一个字符串类型的值。构造函数本身是一个表达式,其类型将是我们刚刚为其定义变体的类型。
但是,如果我们查看 流水线操作符的类型(|>) ...它是一个函数类型。
(|>);;
- : 'a -> ('a -> 'b) -> 'b = <fun>
并且它需要一个函数类型作为它的第二个参数。
然而,在它被破坏的情况下,传递的类型实际上是一个类型代码,它不是一个函数类型,因此是一个类型不匹配......并且编译器大喊加载,我们可以在产生的错误中看到。
OCaml 区分了函数应用程序和构造函数应用程序。
变体构造函数应用程序的语法是C (x_1, ..., x_n)
。
因此表达式
s |> Ticker
被解析为
(|>) (s) (Ticker)
其中 Ticker
缺少参数。
有人可能想知道为什么 OCaml 不像 Haskell 那样统一函数和构造函数应用程序。对这种差异的一种部分解释是,这是允许突变的结果。
事实上,在存在突变的情况下(因此具有(宽松的)值限制),变体构造函数应用程序与 OCaml 中的函数应用程序不具有完全相同的语义。
例如,如果我将包装器类型定义为
type 'a w = W of 'a
let int_minus = (~-)
let float_minus = (~-.)
下面的例子:
let ok =
let x = W Fun.id in
[x; W int_minus], [x; W float_minus]
打字很好。但是,如果我替换构造函数应用程序
通过构造函数
let w x = W x
在这个例子中
let error =
let x = w Fun.id in
[x; w int_minus], [x; w float_minus]
由于值限制,这会触发错误:
Error: This expression has type (float -> float) w
but an expression was expected of type (int -> int) w
Type float is not compatible with type int
主要区别在于泛型函数可能使用内部可变引用。因此
的类型
let x = w Fun.id
是 ('_weak1 -> '_weak1) w
,其中 _weak1
是一个弱多态类型变量(又名具体类型的占位符)。这个占位符类型在我写[x; w int_minus]
的时候和int
是统一的。然后,稍后尝试构建 [x; w float_minus]
会产生错误,因为我正在尝试将 x
与类型 (float->float) w
.
一起使用
相反,变体构造函数应用程序不能进行任何计算,因此不受此限制和类型
let x = W Fun.id
是预期的完全多态类型 ('a -> 'a) w
。因此,我可以在
中为 'a
重用两种不同类型的 x
[x; W int_minus], [x; W float_minus]
(请参阅 https://ocaml.org/manual/polymorphism.html#s:weak-polymorphism 以获得更详尽的解释)。
学习 OCaml,想知道为什么编译器认为我向单参数类型构造函数提供零参数。
这个 OCaml:
open Core
module Json = Yojson.Safe.Util
type ticker = Ticker of string
let ticker_of_yojson s =
s |> Json.to_string |> Ticker |> Result.Ok
产生此错误:
The constructor Ticker expects 1 argument(s)
but is applied here to 0 argument(s).
如果我把它改成这样,用 lambdas 包装构造函数调用,
let ticker_of_yojson s =
s |> Json.to_string |> (fun x -> Ticker x) |> (fun x -> Result.Ok x)
它编译。如果我只将 Ticker
构造函数调用包装在 lambda 中,我会得到与 Result.Ok
.
编译器在这里缺少什么,用 lambda 表达式替换可以解决?是否还有其他我可以添加的东西,以便没有 lambda 的原始版本可以工作?
我看到了另一个 SO post,这似乎是一个类似的问题,但我无法将两种情况联系起来:ocaml type constructor arguments
感谢您的宝贵时间 - 任何帮助表示感谢。
OCaml 构造函数不是函数,语言就是这样工作的。从语法上讲,一元构造函数后面需要一个表达式。所以你不能把一个构造函数本身当作一个函数来使用,你需要按照你说的那样把它包装在一个lambda中。
二元(或三元等)构造函数需要在其后加括号的逗号分隔表达式列表。所以你也不能在 OCaml 中部分应用构造函数。
其他语言(特别是 Haskell)将构造函数视为任何其他(柯里化)函数,并且效果非常好。但此时更改 OCaml 可能为时已晚。
Ticker 是一个构造函数,通常用于定义创建特定类型值的方法。游览 Variants in OCaml.
如果我们看一下 Ticker
的定义# type ticker = Ticker of string;;
type ticker = Ticker of string
本质上,我们正在定义一个名为 ticker 的类型,其值可以使用右侧的构造函数 Ticker 创建,它采用一个字符串类型的值。构造函数本身是一个表达式,其类型将是我们刚刚为其定义变体的类型。
但是,如果我们查看 流水线操作符的类型(|>) ...它是一个函数类型。
(|>);;
- : 'a -> ('a -> 'b) -> 'b = <fun>
并且它需要一个函数类型作为它的第二个参数。
然而,在它被破坏的情况下,传递的类型实际上是一个类型代码,它不是一个函数类型,因此是一个类型不匹配......并且编译器大喊加载,我们可以在产生的错误中看到。
OCaml 区分了函数应用程序和构造函数应用程序。
变体构造函数应用程序的语法是C (x_1, ..., x_n)
。
因此表达式
s |> Ticker
被解析为
(|>) (s) (Ticker)
其中 Ticker
缺少参数。
有人可能想知道为什么 OCaml 不像 Haskell 那样统一函数和构造函数应用程序。对这种差异的一种部分解释是,这是允许突变的结果。
事实上,在存在突变的情况下(因此具有(宽松的)值限制),变体构造函数应用程序与 OCaml 中的函数应用程序不具有完全相同的语义。
例如,如果我将包装器类型定义为
type 'a w = W of 'a
let int_minus = (~-)
let float_minus = (~-.)
下面的例子:
let ok =
let x = W Fun.id in
[x; W int_minus], [x; W float_minus]
打字很好。但是,如果我替换构造函数应用程序 通过构造函数
let w x = W x
在这个例子中
let error =
let x = w Fun.id in
[x; w int_minus], [x; w float_minus]
由于值限制,这会触发错误:
Error: This expression has type (float -> float) w but an expression was expected of type (int -> int) w Type float is not compatible with type int
主要区别在于泛型函数可能使用内部可变引用。因此
的类型let x = w Fun.id
是 ('_weak1 -> '_weak1) w
,其中 _weak1
是一个弱多态类型变量(又名具体类型的占位符)。这个占位符类型在我写[x; w int_minus]
的时候和int
是统一的。然后,稍后尝试构建 [x; w float_minus]
会产生错误,因为我正在尝试将 x
与类型 (float->float) w
.
相反,变体构造函数应用程序不能进行任何计算,因此不受此限制和类型
let x = W Fun.id
是预期的完全多态类型 ('a -> 'a) w
。因此,我可以在
'a
重用两种不同类型的 x
[x; W int_minus], [x; W float_minus]
(请参阅 https://ocaml.org/manual/polymorphism.html#s:weak-polymorphism 以获得更详尽的解释)。