#haskell
#haskell
Вопрос:
Рассмотрим следующий метод для создания перечисления с начала 1 в Haskell:
data Level = Lower | Middle | Upper
deriving (Show, Eq, Ord)
instance Enum Level where
toEnum 1 = Lower
toEnum 2 = Middle
toEnum 3 = Upper
fromEnum Lower = 1
fromEnum Middle = 2
fromEnum Upper = 3
instance Bounded Level where
minBound = Lower
maxBound = Upper
Я бы предпочел не делать следующее:
data Level = DontUseThis | Lower | Middle | Upper
deriving (Show, Eq, Ord)
Если нет, есть ли более простой способ сделать это?
Комментарии:
1. Почему вы хотите, чтобы это смещение было на единицу?
2. Что вы на самом деле пытаетесь здесь сделать, что имеет значение
fromEnum minBound
, возвращает ли 0 или 1?3. Это все еще не перечисление с начала 1, это перечисление с начала ниже.
4. Написанный вами код выглядит для меня совершенно нормально. Это правильно, это быстро, и для чтения требуется чертовски мало нейронов.
5. @Ana: возможно, явная функция преобразования
:: Level -> Int
имеет больше смысла, чем использованиеEnum
then.
Ответ №1:
Прежде всего, вам не нужно определять Bounded
экземпляр самостоятельно. Если вы добавите Bounded
в список производных классов типов, вы должны получить идентичное поведение.
Во-вторых, самый простой способ, который я могу придумать для достижения этой цели, — просто вывести Enum
, а затем определить ваши собственные функции перевода. Итак, что-то вроде этого:
data Level = Lower | Middle | Upper
deriving (Show, Eq, Ord, Bounded, Enum)
toEnum' x = toEnum (x - 1)
fromEnum' x = (fromEnum x) 1
Комментарии:
1. Не кажется чистым, но хорошая идея. Можно ли скрыть исходные toEnum и fromEnum и заменить их новыми версиями?
2. Вроде того? Вы можете добавить
import Prelude hiding (toEnum, fromEnum)
вверху, а затем добавить свои собственные определения этих функций. Это выглядит очень похоже на ваш исходный код, но преимущество заключается в том, что остальные 4 функции вEnum
классе типов определены для вас.
Ответ №2:
Вы можете написать это немного более лаконично (ну, если у вас более 3 конструкторов), используя:
import Data.List (elemIndex)
import Data.Maybet (fromJust)
values = [Lower, Middle, Upper]
instance Enum Level where
toEnum n = values !! (n-1)
fromEnum k = 1 fromJust $ elemIndex k values
Комментарии:
1. Однако это довольно дорого с точки зрения времени поиска.
2. Если это действительно проблема, вы всегда можете использовать a
Map
и aVector
вместо этого.