Haskell 具有可见性约束的构造函数或工厂方法中的守卫
Guards in a Haskell constructor or factory methods with visibility constraints
我对 Haskell 比较陌生,在进行实验时我遇到了一个问题,看起来我想在构造函数中使用守卫。我的真实实验有点复杂,但归结为
data X a = Zero
| a==0 = Zero
| otherwise = Some a
我知道这是错误的语法,特别是因为 a
是类型变量,而不是值变量,所以 a==0
无论如何都是无意义的。
背景是值Zero
和Some 0
在所有方面都应该相等,我什至可以说相同。事实上,我从来不想构造一个 Some 0
,这应该被禁止,或者像上面起草的那样,在构造函数中已经悄悄地转换为 Zero
。
我认为 Haskell 中有一个常见的成语。在 Java 中,我只会创建两个构造函数 private
并提供工厂方法来创建一个或另一个 some(0)
返回 Zero
而不是 Some(0)
。 Haskell 你也是这样吗?
编辑:好的,谷歌搜索更多我终于找到了 Haskell Factory Function entry,这似乎是答案的一部分。
要将构造函数设为私有,只需不要将其导出即可,例如:
module Foo (Bar, mkBar) where
data Bar = Zero | Some a | ...
mkBar :: Int -> Bar -- exported smart constructor
mkBar a = ...
库的用户可以使用 mkBar
函数创建 Bar
,但不能使用 Zero
或 Some ...
。
关键是导出列表中的Bar
。如果您指定:
module Foo (Bar(..), ...) where
那么 Bar
的构造函数也将被导出。
In Java I would just make the two constructors private and provide factory methods to create either one or the other
介绍了如何通过在 Haskell 中做类似的事情来解决您的问题。我只想指出一个容易混淆的问题。在你的伪Haskell片段中...
data X a = Zero
| a==0 = Zero
| otherwise = Some a
...您正在将 data X a
中的 a
视为 X
值的构造函数的参数,以便您能够例如测试是否a == 0
。但是,a
是一个 type 参数。它可以被不同的类型代替,所以X a
实际上对应了X Int
、X Double
、X String
等一系列类型。这与您如何使用 Java 泛型来参数化 class 非常相似,如在 class X<A>
.
等声明中
使用通用术语,X
是一个 类型构造函数 ,它接受一个类型并生成另一个类型(例如从 Int
到 X Int
). value(或data)构造函数是您在等号后指定的构造函数。如您所知,您可以将它们用作常规值,它们可能是也可能不是函数,具体取决于它们是否接受参数。所以如果我们这样做...
GHCi> data X a = Zero | Some a
... 那么 Zero
是一个 X a
类型的值,用于任意 a
...
GHCi> :t Zero
Zero :: X a
... 而 Some
是从 a
到 X a
的函数:
GHCi> :t Some
Some :: a -> X a
至于类型构造函数X
,我们不说它的类型,而是说它的种类。类型和类型构造函数的种类类似于值的类型。 GHCi 中的 :kind
(或 :k
)命令允许您检查类型:
GHCi> :k Int
Int :: *
GHCi> :k X
X :: * -> *
* -> *
表示 X
取一个类型并产生一个类型,如上所述。
我对 Haskell 比较陌生,在进行实验时我遇到了一个问题,看起来我想在构造函数中使用守卫。我的真实实验有点复杂,但归结为
data X a = Zero
| a==0 = Zero
| otherwise = Some a
我知道这是错误的语法,特别是因为 a
是类型变量,而不是值变量,所以 a==0
无论如何都是无意义的。
背景是值Zero
和Some 0
在所有方面都应该相等,我什至可以说相同。事实上,我从来不想构造一个 Some 0
,这应该被禁止,或者像上面起草的那样,在构造函数中已经悄悄地转换为 Zero
。
我认为 Haskell 中有一个常见的成语。在 Java 中,我只会创建两个构造函数 private
并提供工厂方法来创建一个或另一个 some(0)
返回 Zero
而不是 Some(0)
。 Haskell 你也是这样吗?
编辑:好的,谷歌搜索更多我终于找到了 Haskell Factory Function entry,这似乎是答案的一部分。
要将构造函数设为私有,只需不要将其导出即可,例如:
module Foo (Bar, mkBar) where
data Bar = Zero | Some a | ...
mkBar :: Int -> Bar -- exported smart constructor
mkBar a = ...
库的用户可以使用 mkBar
函数创建 Bar
,但不能使用 Zero
或 Some ...
。
关键是导出列表中的Bar
。如果您指定:
module Foo (Bar(..), ...) where
那么 Bar
的构造函数也将被导出。
In Java I would just make the two constructors private and provide factory methods to create either one or the other
data X a = Zero
| a==0 = Zero
| otherwise = Some a
...您正在将 data X a
中的 a
视为 X
值的构造函数的参数,以便您能够例如测试是否a == 0
。但是,a
是一个 type 参数。它可以被不同的类型代替,所以X a
实际上对应了X Int
、X Double
、X String
等一系列类型。这与您如何使用 Java 泛型来参数化 class 非常相似,如在 class X<A>
.
使用通用术语,X
是一个 类型构造函数 ,它接受一个类型并生成另一个类型(例如从 Int
到 X Int
). value(或data)构造函数是您在等号后指定的构造函数。如您所知,您可以将它们用作常规值,它们可能是也可能不是函数,具体取决于它们是否接受参数。所以如果我们这样做...
GHCi> data X a = Zero | Some a
... 那么 Zero
是一个 X a
类型的值,用于任意 a
...
GHCi> :t Zero
Zero :: X a
... 而 Some
是从 a
到 X a
的函数:
GHCi> :t Some
Some :: a -> X a
至于类型构造函数X
,我们不说它的类型,而是说它的种类。类型和类型构造函数的种类类似于值的类型。 GHCi 中的 :kind
(或 :k
)命令允许您检查类型:
GHCi> :k Int
Int :: *
GHCi> :k X
X :: * -> *
* -> *
表示 X
取一个类型并产生一个类型,如上所述。