[英]Enum instance for tuples in Haskell
我想定義一個元組(x, y)
作為Enum
類的實例,因為知道x
和y
都是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
在上一行中, x
和y
都是類型(類型變量)。
toEnum = y
enumFrom x = (x, x)
在以上兩行中, x
和y
都是值((值)變量)。 y
-as-a-value尚未在任何地方定義,這就是它在范圍內的含義。
至於如何聲明這樣的實例,例如,我不確定您希望fromEnum
和toEnum
的行為如何。
如果問我,這不是一個好主意,但是無論如何-
要創建類型類的實例,您需要查看簽名。
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 x
和Enum 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)
使用fromEnum
和toEnum
,所有其他功能都相當簡單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.