Haskell 中所有 a(正常值)的新类型?
A new type for all a (normal value) and nothing in Haskell?
我要
- 创建一个新的类型和值来指示
none
就像 Maybe
的 Nothing
。
- 为所有
a
(正常值)和 none
创建一个新的联合类型
- 创建一个接受新联合类型的函数,然后如果参数是
none
什么都不做。
不使用 Maybe
,我如何在 Haskell 中执行此操作?
在打字稿中
const none = { undefined };
type None = typeof none;
type Option<T> = None | T;
type f = <T>(a:Option<T>) => any;
const f:f = a =>
a === none
? undefined
: console.log(a);
如何在 Haskell 中执行此操作?为了以防万一,请注意,我不是在问如何使用 Maybe
Monad。谢谢。
如果你有一个你试图解决的实际编程问题,它需要你表示“要么是 T 类型的值,要么什么都不是”的概念,那么 Haskell 的答案是使用 Maybe T
.
无论您的代码的目标是什么,如果在 Typescript 中您会使用 Option
来实现该目标,那么在 Haskell 中您可以使用 Maybe
来实现该目标。代码会有些不同,但这并不奇怪,因为它们是不同的语言。
但是,如果您尝试直接使用 Typescript 中涉及的概念 Option
,在 Haskell 中实现一个完全相同的类型(而不是作为一个解决问题的工具),那么你就倒霉了。 Haskell 没有 联合类型的概念,也没有很容易模拟 one1.[=65 的方法=]
你可以 sort-of 试试 Typeable
:
import Data.Typeable (Typeable, cast)
data None = None
f :: (Typeable a, Show a) => a -> IO ()
f x = case (cast x :: Maybe None)
of Just None -> pure ()
Nothing -> print x
当我们有一个 Typeable
约束在起作用时,我们实际上可以检查一个值是否属于某种类型(如果是,则在引用具有正确类型的地方获取对它的引用,所以我们可以将其用作该类型)。但这迫使我们无论如何都要通过 Maybe
,因为 cast
需要一种方法来表示未成功的转换的值!
这也很棘手,因为现在我们的 None
类型的实际参数根本无法表示,而 Maybe
选项可以很好地表示 Just Nothing
。的确,您 经常 需要这种“嵌套 failure-or-absence” 功能(尽管绝不是永远不会;想想一个可能不会 return 结果的查询: 如果您需要区分 运行 查询失败与 return 查询无结果,那很自然 Maybe (Maybe Result)
)。但我更喜欢我处理任何类型的设施来处理 any 类型,具有一致性。根据设计,如果没有任何极端情况,您就不会被奇怪的极端情况所困扰。
而且您不能更一般地使用 Typeable
来实际声明一个类型,该类型可能是两个特定类型的联合;你必须接受带有 Typeable
约束的类型变量 a
,这意味着人们可以传递给你 any 类型,而不仅仅是你试图放入的两个一个工会。由于您只能编写有限数量的 cast
s,因此 Typeable
从根本上只能用于专门处理一组特定类型,或者其他任何内容的代码路径(可能会出错) .
作为更一般的观点,您需要避免使用 over-using Typeable
,以便编写能够获得 Haskell 类型系统的所有好处的代码。许多 Haskell 代码使用的属性产生于您 不能 对多态类型执行的操作,因为您不知道它是哪种具体类型。当 Typeable
正在播放时,所有这些都在 window 之外。举一个非常简单的例子,有一个经典的论点,即只有一个 a -> a
类型的函数(不会触底);由于无法知道类型 a
是什么,该函数的实现无法无中生有,因此它只能 return 未修改。但是函数类型 Typeable a => a -> a
可以有任意数量的古怪规则编码,例如“如果参数是 Integer
,则向其添加一个”。无论实现中隐藏了什么,它都不会反映在 Typeable
约束之外的类型中,因此您必须熟悉实现的细节才能使用此函数,编译器不会发现你是否犯了错误。这种效果的一个明显例子是,在我尝试编写上面的 f
时,我们最终得到了 f :: Typeable a => a -> IO ()
类型;有 zero 指示它期望使用的类型(它想要处理“None
或任何其他”)。
作为一个完全不同的轨道,你当然可以这样做:
data None = None
data Option a = Some a | None' None
现在您已经“创建了一个不代表任何内容的新类型”和“为所有 a
(正常值)和 none 创建了一个新的联合类型”。但是 Haskell 的 ADT 是 discrimated 联合,这意味着在每个变体上总会有一个构造函数标签(在 运行 时间和你的源代码中)工会。
所以使用单独的 None
类型真的没有意义,因为一旦您在 Option a
值中看到 None'
标记,您就已经知道所有需要知道的了关于价值;查看 None
值,发现它是 None
并没有告诉您任何信息 2。所以你不妨使用:
data Option a = Some a | None
与内置 Maybe
完全相同,仅在选择的名称上有所不同。
类似地,您显然可以编写一个函数,其中包含一个 Option
为 None
时要处理的案例,以及一个有内容时要处理的案例(其中任何一个都可以“什么都不做” ,如果您 return 是一种“做某事”有意义的类型,即某种动作,例如 IO
或 State
).
f :: Show a => Option a -> IO a
f None = pure ()
f (Some a) = print a
代码略有不同,甚至忽略了琐碎的语法和命名问题;我们ad 以引用 Some
构造函数并在 中的值 上调用 print
,而不是直接将参数打印到 f
3。 Haskell 使用类型类将类型分为可以有意义地打印的类型和不能打印的类型,并且只允许您在前者上调用 print
。但它是如此接近,以至于我毫无保留地说“这相当于 Haskell 你写的 Typescript”。
鉴于 Maybe
已经存在,您不妨使用它。 (同样,如果你需要它,内置类型 ()
除了名称之外 - 与 data None = None
相同。)但是再说一次:如果你试图解决一个问题,那就是你要做的你会在 Typescript 中使用 Option
for;相反,如果您的目标是实现与 Option
完全相同的东西 ,那么您根本无法使用 Haskell 提供的工具。
1 你可以 可能 使用不安全的功能(比如 unsafeCoerce
往返 Any
).我不知道如何才能使它可用和可靠,这样做对于任何 实用 目的来说都是浪费时间;你永远不会在真正的程序中使用这样的代码,这只是一个有趣的练习,你可以在多大程度上破解语言实现。所以我不会写一个解决这个角度的答案。
2 嗯,从技术上讲,它告诉你产生它的计算终止了;它可能是底部。但是你不能用这些信息做任何事情,因为不可能 test 它是否是底部;如果是,你也会出错(或不终止)。
3 将整个参数打印到 f
也可以,它只会打印出来,例如Some "value"
,我想这不是你的意思。
我要
- 创建一个新的类型和值来指示
none
就像Maybe
的Nothing
。 - 为所有
a
(正常值)和none
创建一个新的联合类型
- 创建一个接受新联合类型的函数,然后如果参数是
none
什么都不做。
不使用 Maybe
,我如何在 Haskell 中执行此操作?
在打字稿中
const none = { undefined };
type None = typeof none;
type Option<T> = None | T;
type f = <T>(a:Option<T>) => any;
const f:f = a =>
a === none
? undefined
: console.log(a);
如何在 Haskell 中执行此操作?为了以防万一,请注意,我不是在问如何使用 Maybe
Monad。谢谢。
如果你有一个你试图解决的实际编程问题,它需要你表示“要么是 T 类型的值,要么什么都不是”的概念,那么 Haskell 的答案是使用 Maybe T
.
无论您的代码的目标是什么,如果在 Typescript 中您会使用 Option
来实现该目标,那么在 Haskell 中您可以使用 Maybe
来实现该目标。代码会有些不同,但这并不奇怪,因为它们是不同的语言。
但是,如果您尝试直接使用 Typescript 中涉及的概念 Option
,在 Haskell 中实现一个完全相同的类型(而不是作为一个解决问题的工具),那么你就倒霉了。 Haskell 没有 联合类型的概念,也没有很容易模拟 one1.[=65 的方法=]
你可以 sort-of 试试 Typeable
:
import Data.Typeable (Typeable, cast)
data None = None
f :: (Typeable a, Show a) => a -> IO ()
f x = case (cast x :: Maybe None)
of Just None -> pure ()
Nothing -> print x
当我们有一个 Typeable
约束在起作用时,我们实际上可以检查一个值是否属于某种类型(如果是,则在引用具有正确类型的地方获取对它的引用,所以我们可以将其用作该类型)。但这迫使我们无论如何都要通过 Maybe
,因为 cast
需要一种方法来表示未成功的转换的值!
这也很棘手,因为现在我们的 None
类型的实际参数根本无法表示,而 Maybe
选项可以很好地表示 Just Nothing
。的确,您 经常 需要这种“嵌套 failure-or-absence” 功能(尽管绝不是永远不会;想想一个可能不会 return 结果的查询: 如果您需要区分 运行 查询失败与 return 查询无结果,那很自然 Maybe (Maybe Result)
)。但我更喜欢我处理任何类型的设施来处理 any 类型,具有一致性。根据设计,如果没有任何极端情况,您就不会被奇怪的极端情况所困扰。
而且您不能更一般地使用 Typeable
来实际声明一个类型,该类型可能是两个特定类型的联合;你必须接受带有 Typeable
约束的类型变量 a
,这意味着人们可以传递给你 any 类型,而不仅仅是你试图放入的两个一个工会。由于您只能编写有限数量的 cast
s,因此 Typeable
从根本上只能用于专门处理一组特定类型,或者其他任何内容的代码路径(可能会出错) .
作为更一般的观点,您需要避免使用 over-using Typeable
,以便编写能够获得 Haskell 类型系统的所有好处的代码。许多 Haskell 代码使用的属性产生于您 不能 对多态类型执行的操作,因为您不知道它是哪种具体类型。当 Typeable
正在播放时,所有这些都在 window 之外。举一个非常简单的例子,有一个经典的论点,即只有一个 a -> a
类型的函数(不会触底);由于无法知道类型 a
是什么,该函数的实现无法无中生有,因此它只能 return 未修改。但是函数类型 Typeable a => a -> a
可以有任意数量的古怪规则编码,例如“如果参数是 Integer
,则向其添加一个”。无论实现中隐藏了什么,它都不会反映在 Typeable
约束之外的类型中,因此您必须熟悉实现的细节才能使用此函数,编译器不会发现你是否犯了错误。这种效果的一个明显例子是,在我尝试编写上面的 f
时,我们最终得到了 f :: Typeable a => a -> IO ()
类型;有 zero 指示它期望使用的类型(它想要处理“None
或任何其他”)。
作为一个完全不同的轨道,你当然可以这样做:
data None = None
data Option a = Some a | None' None
现在您已经“创建了一个不代表任何内容的新类型”和“为所有 a
(正常值)和 none 创建了一个新的联合类型”。但是 Haskell 的 ADT 是 discrimated 联合,这意味着在每个变体上总会有一个构造函数标签(在 运行 时间和你的源代码中)工会。
所以使用单独的 None
类型真的没有意义,因为一旦您在 Option a
值中看到 None'
标记,您就已经知道所有需要知道的了关于价值;查看 None
值,发现它是 None
并没有告诉您任何信息 2。所以你不妨使用:
data Option a = Some a | None
与内置 Maybe
完全相同,仅在选择的名称上有所不同。
类似地,您显然可以编写一个函数,其中包含一个 Option
为 None
时要处理的案例,以及一个有内容时要处理的案例(其中任何一个都可以“什么都不做” ,如果您 return 是一种“做某事”有意义的类型,即某种动作,例如 IO
或 State
).
f :: Show a => Option a -> IO a
f None = pure ()
f (Some a) = print a
代码略有不同,甚至忽略了琐碎的语法和命名问题;我们ad 以引用 Some
构造函数并在 中的值 上调用 print
,而不是直接将参数打印到 f
3。 Haskell 使用类型类将类型分为可以有意义地打印的类型和不能打印的类型,并且只允许您在前者上调用 print
。但它是如此接近,以至于我毫无保留地说“这相当于 Haskell 你写的 Typescript”。
鉴于 Maybe
已经存在,您不妨使用它。 (同样,如果你需要它,内置类型 ()
除了名称之外 - 与 data None = None
相同。)但是再说一次:如果你试图解决一个问题,那就是你要做的你会在 Typescript 中使用 Option
for;相反,如果您的目标是实现与 Option
完全相同的东西 ,那么您根本无法使用 Haskell 提供的工具。
1 你可以 可能 使用不安全的功能(比如 unsafeCoerce
往返 Any
).我不知道如何才能使它可用和可靠,这样做对于任何 实用 目的来说都是浪费时间;你永远不会在真正的程序中使用这样的代码,这只是一个有趣的练习,你可以在多大程度上破解语言实现。所以我不会写一个解决这个角度的答案。
2 嗯,从技术上讲,它告诉你产生它的计算终止了;它可能是底部。但是你不能用这些信息做任何事情,因为不可能 test 它是否是底部;如果是,你也会出错(或不终止)。
3 将整个参数打印到 f
也可以,它只会打印出来,例如Some "value"
,我想这不是你的意思。