Не очень хорошая идея, если вы спросите меня, но в любом случае -
Чтобы создать экземпляр класса типов, вам нужно посмотреть на сигнатуры.
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]
Так что в вашемcase
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 ]
Чтение комментария Дитриха Эппа
На самом деле невозможно создать полезные Enum (x, y)
из Enum x
и Enum 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
кортежей.Все остальные кортежи (x,y)
с max x y == 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
.j
получается аналогично, просто с div 2
от остатка.
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
все остальные функции довольно тривиальны.