gpt4 book ai didi

Haskell:是否可以使用数字作为数据构造函数?

转载 作者:行者123 更新时间:2023-12-02 16:32:26 25 4
gpt4 key购买 nike

我有一些数据,我想测试一下存储它们的最佳方式是什么。我正在二进制、四进制、八进制和十六进制数据类型之间做出选择。

检查哪个是最好的唯一方法是在我的算法中使用它们中的每一个,然后查看结果。

到目前为止,我的实现如下所示:

{-# LANGUAGE DeriveAnyClass #-}

data Binary = O | I
deriving (Bounded, Enum, Eq, Ord, Show)
data Octal = OA | OB | OC | OD | OE | OF | OG | OH
deriving ( ... )

但我想要更通用的构造函数,例如 data Binary = 0 | 1..可以这样做吗?

最佳答案

不可能获得您想要的确切语法,但有一些方法可以以共享构造函数的方式一般定义“0 到 n 之间”的类型,然后使用数字文字作为抽象构造函数。

finite-typelits包提供了一个根据其元素数量参数化的类型,因此:

x :: Finite 4

将是一个有四个居民的类型:0、1、2和3。如果您有一个Finite 4类型的值,您可以确定它是这四个值之一(或者一些愚蠢的东西,比如 undefined 或其他一些底部)。您无法直接对其进行模式匹配,但可以使用 getFinite::Finite n -> IntegerFinite 4 投影到整数中。

因此,在这个方案中,您将:

type Binary = Finite 2
type Quad = Finite 4
type Octal = Finite 8

您可以间接进行模式匹配:

processBinary :: Binary -> String
processBinary d = case getFinite d of
0 -> "It's a zero"
1 -> "it's a one"
_ -> -- this case should be impossible, even though the compiler can't verify that.

而且,您甚至可以使用其(部分)Num 实例使用数字文字“构造”它们:

> putStrLn (processBinary 0)
It's a zero
> putStrLn (processBinary 0)
It's a one

所以这可能是最接近您想要的东西!但也有一些缺点——编译器无法验证您的模式匹配语句是否完整,也无法验证您的数字文字是否确实有效,并且不会超出您的类型的范围。正在使用。

> putStrLn (processBinary 2)
** Error: Runtime error! Sucks :'(

还有方便的 weakenNstrengthenN 函数,它们允许您像使用 Finite 一样使用 Finite 2 8(使用二进制数字,就好像它是八进制数字一样),也可以使用Finite 8,就好像它是Maybe (Finite 2) .

binDigitToOctalDigit :: Binary -> Octal   -- Finite 2 -> Finite 8
binDigitToOctalDigit = weakenN
<小时/>

还有另一种方法与您想要的不完全匹配,但有一些优点。您可以做的是拥有一个递归/归纳定义的定义类型(如列表),该类型被“构造”为仅具有这么多构造函数,并在某些类型级数字上再次参数化。 type-combinators提供了一种这样的类型。在那里,你会:

type Binary = Fin (S (S Z))     -- "2"
type Octal = Fin (S (S (S (S (S (S (S (S Z)))))))) -- "8"

该库确实提供了方便的类型同义词,因此您可以改为编写:

type Binary = Fin N2
type Quad = Fin N4
type Octal = Fin N8

并且 Fin 类型被构造为具有该类型指示的构造函数的数量。 Fin N2 有两个构造函数:

  1. FZ::Fin N2
  2. FS FZ::Fin N2

Fin N8有八个构造函数,FZFS FZFS (FS FZ)等.

Fin 也有一个投影函数,fin::Fin n -> Int,因此您可以像使用 一样使用它FiniteInt 文字上的模式匹配。 但是!这样做的好处是你还可以直接在构造函数上进行模式匹配,编译器将确保完整性:

processBinary :: Fin N2 -> String
processBinary d = case d of
FZ -> "It's a zero"
FS FZ -> "It's a one"

GHC 实际上可以验证您是否已经处理了每个选项:)

而且,您也永远不会意外地使用“超出范围”的构造函数:

> putStrLn (processBinary FZ)
It's a zero
> putStrLn (processBinary (FS (FS FZ))
-- that is a compile error! neat, the compiler would tell you that this isn't allowed!

该库定义的weakenfinite-typelits库的定义类似。它没有定义strengthen,但如果您需要的话可以实现它:)

binDigitToQuadDigit :: Binary -> Quad      -- Fin N2 -> Fin N4
binDigitToQuadDigit = weaken . weaken

关于Haskell:是否可以使用数字作为数据构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39941395/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com