【问题标题】:How do I map each value from one list to another? (Haskell)如何将每个值从一个列表映射到另一个? (哈斯克尔)
【发布时间】:2018-11-30 00:15:33
【问题描述】:

这是我目前的代码:

data Suit = Diamond | Club | Heart | Spade
  deriving (Read, Enum, Eq, Bounded)

data Rank = Two | Three | Four
     | Five | Six | Seven | Eight | Nine | Ten 
     | Jack | Queen | King | Ace
  deriving (Read, Enum, Eq, Ord, Bounded)

我正在尝试将每个值(无论是 Rank 还是 Suit)映射到一个唯一的素数。

primeMapper :: Either Rank Suit -> Int

应该是最后一个函数,我想遍历每个 Suit 并将其设置为前四个素数:

primeMapper [Diamond .. Spade] = [2,3,5,7]

并且每个 Rank 等于 17 号之前的其余素数:

primeMapper [Two .. Ace] = drop 4 . take 17 $ primes

假设我有一个名为 primes 的生成函数。

然而,这段代码显然会抛出错误,因为它从列表中生成了一个列表。我怎样才能实现我想要做的事情?让我知道我是否可以更好地解释它。

最终目标是拥有一个哈希表,根据素因数为每张牌赋予唯一的 ID,然后生成素因数分解并使用模数来快速比较扑克手牌。

【问题讨论】:

  • 你有学习haskell的好资源(一本书)吗?你会想要加快模式匹配的速度。让你开始的东西:primeMapper (Left Two) = undefined ; primeMapper (Right Diamond) = undefined ; ...etc。还阅读了 Enum 类

标签: list haskell primes poker


【解决方案1】:

最终我这样解决了我想要做的事情:

primeMapper :: Either Suit Rank -> Int
primeMapper x = case x of
        Left Diamond -> 2
        Left Club -> 3
        Left Heart -> 5
        Left Spade -> 7
        Right Two -> 11
        Right Three -> 13
        Right Four -> 17
        Right Five -> 19
        Right Six -> 23
        Right Seven -> 29
        Right Eight -> 31
        Right Nine -> 37
        Right Ten -> 41
        Right Jack -> 43
        Right Queen -> 47
        Right King -> 53
        Right Ace -> 59

...有没有比手写每个案例更简洁的方法?

【讨论】:

  • 更简洁的方式:[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59] !! case x of Left s -> fromEnum s; Right r -> 4 + fromEnum r.
  • 更简洁:([2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59] !!) . either fromEnum ((+4) . fromEnum)(尽管现在我们正在突破可读性的极限)。
【解决方案2】:

您使用模式匹配的解决方案是最好的,但我更喜欢

primeMapper :: Either Suit Rank -> Int
primeMapper (Left Diamond) = 2
primeMapper (Left Club)    = 3
...

而不是你冗长的case 表达式。

不过你也可以使用lookup :: Eq a => a -> [(a, b)] -> Maybe b

import Data.Maybe (fromJust)

primeMapper :: Either Suit Rank -> Int
primeMapper = fromJust . flip lookup zippedPrimes
  where
  zippedPrimes = zip suitranks primes
  suitranks    = fmap Left suits ++ fmap Right ranks :: [Either Suit Rank]
  suits        = fromEnum minBound
  ranks        = fromEnum minBound

【讨论】:

    【解决方案3】:

    根据您打算使用它的目的,您可能根本不需要使用素数或素数分解;您只需选择一个或另一个西装或等级进行基本转换,就可以快速转换为纯数字和从纯数字转换。在这里我要选花色——有四种花色,所以以 4 为底的第一个数字作为花色,其余数字作为等级。

    encode :: (Suit, Rank) -> Int
    encode (s, r) = fromEnum s + 4 * fromEnum r
    
    decode :: Int -> (Suit, Rank)
    decode n = (toEnum s, toEnum r) where (r, s) = n `quotRem` 4
    

    您可以在 ghci 中验证这是否为每张卡提供了唯一编号:

    > [encode (s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
    [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51]
    

    并且他们正确解码:

    > map decode [0..51] == [(s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
    True
    

    【讨论】:

      【解决方案4】:

      我希望你可以调整其中的一些内容。

      no2s3s5s = \n -> take n $ scanl (\b a -> a+b) 11 $ cycle [2,4,2,4,6,2,6,4]
      rnk = filter (/=49) $ no2s3s5s 14  
      stv = [2,3,5,7]
      _deck = [ b*v | b <- stv, v <- rnk]
      _Dia = take 13.drop (0*13) $ _deck
      _Clb = take 13.drop (1*13) $ _deck
      _Hrt = take 13.drop (2*13) $ _deck
      _Spd = take 13.drop (3*13) $ _deck
      

      _Dia

      [22,26,34,38,46,58,62,74,82,86,94,106,118]

      _Clb

      [33,39,51,57,69,87,93,111,123,129,141,159,177]

      _Hrt

      [55,65,85,95,115,145,155,185,205,215,235,265,295]

      _Spd

      [77,91,119,133,161,203,217,259,287,301,329,371,413]

      _deck

      [22,26,34,38,46,58,62,74,82,86,94,106,118,33,39,51,57,69,87,93,111,123,129,141,159,177,55,65,85,95,115,145,155,13,​​57,205,2575,25,25, 91,119,133,161,203,217,259,287,301,329,371,413]

      length _deck

      52

      您的倍数 (_deck) 都是独一无二的。 我通常使用 no2s3s5s 和计算(有限)因子列表和 mod 函数来生成一个长素数列表。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-09
        • 1970-01-01
        • 2018-10-12
        相关资源
        最近更新 更多