簡體   English   中英

Haskell中元組的枚舉實例

[英]Enum instance for tuples in Haskell

我想定義一個元組(x, y)作為Enum類的實例,因為知道xy都是Enum實例。 以下嘗試:

instance (Enum x, Enum y) => Enum (x, y) where
    toEnum = y
    enumFrom x = (x, x)

僅導致錯誤( y不在范圍內)。 我是Haskell的新手,有人可以解釋如何聲明這樣的實例嗎?

instance (Enum x, Enum y) => Enum (x, y) where

在上一行中, xy都是類型(類型變量)。

    toEnum = y
    enumFrom x = (x, x)

在以上兩行中, xy都是值((值)變量)。 y -as-a-value尚未在任何地方定義,這就是它在范圍內的含義。

至於如何聲明這樣的實例,例如,我不確定您希望fromEnumtoEnum的行為如何。

如果問我,這不是一個好主意,但是無論如何-

要創建類型類的實例,您需要查看簽名。

class Enum a where
  succ :: a -> a
  pred :: a -> a
  toEnum :: Int -> a
  fromEnum :: a -> Int
  enumFrom :: a -> [a]
  enumFromThen :: a -> a -> [a]
  enumFromTo :: a -> a -> [a]
  enumFromThenTo :: a -> a -> a -> [a]

所以你的情況

toEnum :: Int -> (x, y)

但是toEnum = y甚至都沒有定義,因為y只是一個類型,而不是值或構造函數。 可能是

toEnum n = (toEnum 0, toEnum n)

要么

toEnum n = (toEnum n, toEnum n)

要么

toEnum n = (toEnum $ n`div`2, toEnum $ (n+1)`div`2)

至於enumFrom ,您的版本具有簽名

enumFrom :: a -> (a,a)

但是我們需要

enumFrom :: (x,y) -> [(x,y)]

合適的定義取決於toEnum定義方式; 我的第一個建議是

enumFrom (x,y) = [ (x,y') | y' <- enumFrom y ]

閱讀Dietrich Epp的評論

實際上不可能從Enum xEnum y創建有用的Enum (x, y) 您需要其他上下文,例如Bounded x, Bounded y, Enum x, Enum y => Enum (x, y)

我考慮了可以有意義實際完成的方式。 似乎有可能,果然,一個雙射ℤ→ℤ2存在。 我的建議:

[ ...
, (-3,-3), (-3,-2), (-2,-3), (-3,-1), (-1,-3), (-3,0), (0,-3), (-3,1), (1,-3), (-3,2), (2,-3), (-3,3), (3,-3)
, (-2,3), (3,-2), (-1,3), (3,-1)
, (-2,-2), (-2,-1), (-1,-2), (-2,0), (0,-2), (-2,1), (1,-2), (-2,2), (2,-2)
, (-1,2), (2,-1)
, (-1,-1), (-1,0), (0,-1), (-1,1), (1,-1)
, (0,0)
, (1,0), (0,1), (1,1)
, (2,0), (0,2), (2,1), (1,2), (2,2)
, (3,0), (0,3), (3,1), (1,3), (3,2), (2,3), (3,3)
, ... ]

請注意,這降低了雙射ℕ→ℕ2為好,因為其中有些是非常重要的Enum實例不會進入負值區域和別人做。

實現方式:

讓我們創建一個普通的(Int,Int)實例; 很容易將其推廣到您想要的那個。 另外,我只會處理積極的情況。

觀察到在(0,0)和(不包括) (k,0)之間有k^2元組。 max xy == k所有其他元組(x,y) max xy == k其后。 這樣,我們可以定義fromEnum

fromEnum (x,y) = k^2  +  2*j  +  if permuted then 1 else 0
      where k = max x y
            j = min x y
            permuted = y>x

對於toEnum ,我們需要找到此函數的逆函數,即從fromEnum -> n知道我們想知道參數。 k很容易計算為floor . sqrt $ fromIntegral n floor . sqrt $ fromIntegral n 類似地, div 2余數的div 2獲得j

toEnum n =    let k = floor . sqrt $ fromIntegral n
                  (j, permdAdd) = (n-k^2) `divMod` 2
                  permute (x,y) | permdAdd>0  = (y,x)
                                | otherwise    = (x,y)
              in permute (k,j)

使用fromEnumtoEnum ,所有其他功能都相當簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM