Napi Haskell móka

Nem mondom, hogy szép...


data Rank = Ten | Jack | Knight | Queen | King deriving(Show)
data Value = I | II | III | IV | V | VI | VII | VIII | IX | X | 
             XI | XII | XIII | XIV | XV | XVI | XVII | XVIII | XIX | XX | XXI | Skeench deriving(Show)
data Card = Clubs Rank 
            | Diamonds Rank 
            | Spades Rank 
            | Hearts Rank 
            | Tarock Value deriving (Show)
       
cards= foldr (++) [] (map (\x -> map ($ x) [Diamonds, Clubs, Hearts, Spades]) [Ten, Jack, Knight, Queen, King]) ++ 
(map Tarock [I, II,III,IV,V,VI,VII,VIII,IX,X,XI,XII,XIII,XIV,XV,XVI,XVII,XVIII,XIX,XX,XXI,Skeench])

Második megközelítésben:


data Rank = Ten | Jack | Knight | Queen | King deriving(Show,Enum)
data Value = I | II | III | IV | V | VI | VII | VIII | IX | X 
             | XI | XII | XIII | XIV | XV | XVI | XVII | XVIII | XIX | XX 
             | XXI | Skeench deriving(Show,Enum)
data Card = Clubs Rank 
            | Diamonds Rank 
            | Spades Rank 
            | Hearts Rank 
            | Tarock Value deriving (Show)

cards= concatMap (\x -> map ($ x) [Clubs, Hearts, Diamonds, Spades]) [Ten .. King] ++ map Tarock [I .. Skeench]

Alakul ez.

Hozzászólások

foldr (++) az rovidebben concat
concat . map az rovidebben concatMap.

hlint sokat segit ezeknek a megtalalasaban..

np. A masik ami utana jutott eszembe: deriving (Show, Enum, Bounded) es akkor a hosszu felsorolas lecserelheto [minBound .. maxBound] ahelyett hogy [I, II .. ]

mivel a minBound :: (Bounded a) => a barmilyen a -ra igy szukseg lehet egy explicit tipus kiirasra - ha a contextbol nem kovetkezik. vagyis igy [I, II, III ...] -t lecsereled ([minBound .. maxBound] :: [Value])

szerk:

a Bounded -et elhagyva (nem folhasznalva) csak Enum kent:

[I .. Skeench] es akkor nem kell explicit tipus sem - hiszen egyertelmu.

Esetleg igy olvashatobb: [f r | f <- [Clubs, Hearts, Diamonds, Spades], r <- [Ten .. King]] ++ [Tarrock v | v <- [I .. Skeench]]

A Card tipus adat konstruktorai egyvaltozos fuggvenyek:

Clubs :: Rank -> Card
Diamonds :: Rank -> Card
Spades :: Rank -> Card
Hearts :: Rank -> Card
Tarock :: Value -> Card

igy f :: Rank -> Card fv. (a Tarrock kimarad mert annak mas a tipusa). f r :: Card ahol r :: Rank. Egyebkent olyan listat nem is lehet csinalni hogy [ Clubs, Tarrock ] a tipusok miatt. Viszont [Clubs, Diamonds ] :: [ Rank -> Card ] fuggvenyek listaja.

Maga a konstruktor nem lesz folsorolhato mert http://hackage.haskell.org/package/base-4.7.0.2/docs/Prelude.html#t:Enum

class Enum a where
fromEnum :: a -> Int -- fuggveny a problemas. (a toEnum az definialhato lenne).

Megpedig azert mert ha a :: Rank -> Card akkor a fromEnum :: (Rank -> Card) -> Int viszont fv-re nem lehet pattern matchelni. (ill fv-eken nincs Eq sem). Tehat nem tudsz olyat irni, hogy

fromEnum Clubs = ...
fromEnum Hearts = ...

Viszont a Card az lehet enum

cards = [f r | f <- [Clubs, Hearts, Diamonds, Spades], r <- [Ten .. King]] ++ [Tarrock v | v <- [I .. Skeench]]

instance Enum Card where
toEnum n = cards !! n
fromEnum c = fromJust $ elemIndex c cards

es akkor [Clubs Ten .. Tarrock Skeench]. (az elemIndex miatt kell szarmaztatni egy Eq instance-t is mindenhol vagy pattern match-el imlementalni a fromEnum-ot.)

viszont igy az enum osszes trukkje is mukodik: [ Clubs Ten .. Clubs King ], es most csak a Ten-ek: [Clubs Ten, Hearts Ten .. Spades Ten] vagy akar visszafele.

Es megis lehet! A trukk, implementalni fromEnum x -et ha x nem osszehasonlithato, v pattern matchelheto.. (x Ten) viszont igen.


{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances    #-}

data Rank = Ten | Jack | Knight | Queen | King deriving(Show,Enum)
data Value = I | II | III | IV | V | VI | VII | VIII | IX | X 
             | XI | XII | XIII | XIV | XV | XVI | XVII | XVIII | XIX | XX 
             | XXI | Skeench deriving(Show,Enum)
data Card = Clubs Rank 
            | Diamonds Rank 
            | Spades Rank 
            | Hearts Rank 
            | Tarock Value deriving (Show)


type CardConstr = Rank -> Card

instance Enum CardConstr where
  fromEnum x = case x Ten of
    Clubs Ten    -> 0
    Diamonds Ten -> 1
    Spades Ten   -> 2
    Hearts Ten   -> 3
  toEnum n = [ Clubs, Diamonds, Spades, Hearts ] !! n

cards = [f r | f <- [Clubs .. Spades], r <- [Ten .. King]] ++ [Tarock v | v <- [I .. Skeench]]

Hozzateszem, ez elege torott kod, mert az Enum instance-unk azt allitja hogy, fol tudja sorolni a Rank -> Card tipust. De a kododtol fuggetlenul barki egy masik modulban (a Card es a Rank lathatosagat folteve), irhat egy Rank -> Card fv.-t ami a felsorolasbol kimarad.

szerk : meg egy utolso simitas... Mivel az Enumunk eltori a szemantikat - valojaban nem a Rank -> Card tipus elemeit soroljuk fel - igy ez futasi ideju exception:


f Ten = Hearts Queen
fromEnum f

mert a fonti kodban (x Ten) Hearts Queen-t ad. Ha nem matchelunk a Ten -re akor a case mar teljes:


  fromEnum x = case x Ten of
    Clubs _    -> 0
    Diamonds _ -> 1
    Spades _   -> 2
    Hearts _   -> 3

es fromEnum f igy Hearts-ot ad.

szerk2:

A helyes implementacio ez alapjan szinten lehetseges: kepezzuk a Rank -> Card osszes lehetseges lekepezesek listajat valamilyen sorrendben, a toEnum egyszeruen ezt indexeli, a fromEnum meg megnezi hogy a bejovo fuggveny melyik indexuvel adja minden inputra ugyanazt az eredmenyt. Gyors nem lesz, de elmeletileg helyes :)