2015-09-19 2 views
4

Если я объявляю конструкторы данных, такие какфункция Haskell проверить перестановкой

data City = Baltimore | Chicago | Seattle | Miami | Toronto 
     deriving (Bounded, Enum, Eq, Ord, Show) 

data Name = Orioles | Cubs | Mariners | Marlins | BlueJays 
     deriving (Bounded, Enum, Eq, Ord, Show) 

Как я могу сделать функцию

checkPermutation :: (City -> Name) -> Bool 

, чтобы проверить, что никакие два города не присваивается одинаковое имя команды. Например, следующее возвращает True, но если любое «Имя» назначено более чем одному городу, оно вернет False.

test1 :: City -> Name 
test1 c = case c of 
    Baltimore -> Orioles 
    Chicago -> Cubs 
    Seattle -> Mariners 
    Miami  -> Marlins 
    Toronto -> Blue Jays 

ответ

5

Попробуйте это:

import Data.List (nub) 

cities :: [City] 
cities = [Baltimore..Toronto] 

checkPermutation :: (City -> Name) -> Bool 
checkPermutation f = (== length cities) . length . nub . map f $ cities 

Это в основном проверяет, является ли функция f :: City -> Name является injective.

В самом деле, мы можем создать более общий injective предикат:

import Data.Set as Set 

typeSet :: (Bounded a, Enum a, Ord a) => Set a 
typeSet = fromList $ enumFrom minBound 

injective :: (Enum a, Bounded a, Ord a, Ord b) => (a -> b) -> Bool 
injective f = let xs = typeSet in (== size xs) . size . Set.map f $ xs 

Надежда, что помогает.

+4

И вы можете сделать это более эффективным (если это проблема), добавив ограничение 'Ord' и используя наборы вместо' nub'. –

+0

@ ThomasM.DuBuisson Действительно. Я обновил свой ответ. –

+0

Должен ли я поставить этот «checkPermutation f = (== length cities). Length. Nub. Map f $ cities" в инструкции if так или иначе, чтобы я мог вернуть true или false? Кроме того, ghci не нравится «cities = [Baltimore..Toronto]», говоря, что раздел должен быть заключен в круглые скобки, а не в области – Corey

Смежные вопросы