2016-10-22 58 views
1

我只是Haskell的初學者,我嘗試在Haskell中做cryptopals加密挑戰。檢查Maybe值

我寫了下面的代碼:

import Data.Char 

nibbleToInt :: Char -> Int 
nibbleToInt c 
    | ('0' <= c && c <= '9') = (ord c) - 48 
    | ('a' <= c && c <= 'f') = (ord c) - 87 
    | ('A' <= c && c <= 'F') = (ord c) - 55 
    | otherwise = error "Boom" 


hexToInt :: String -> Int 
hexToInt (x:y:[]) = nibbleToInt x * 16 + nibbleToInt y 
hexToInt _ = error "Boom" 

hexToInts :: String -> [Int] 
hexToInts [] = [] 
hexToInts (n1:n2:ns) = [hexToInt $ [n1] ++ [n2]] ++ (hexToInts ns) 
hexToInts _ = error "Boom" 

main = do 
    print $ hexToInts "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d" 

此代碼似乎工作,但我相信它可以提升!

我重構了nibbleToInt功能使用Maybe

nibbleToInt :: Char -> Maybe Int 
nibbleToInt c 
    | ('0' <= c && c <= '9') = Just ((ord c) - 48) 
    | ('a' <= c && c <= 'f') = Just ((ord c) - 87) 
    | ('A' <= c && c <= 'F') = Just ((ord c) - 55) 
    | otherwise = Nothing 

然而,然後,我不知道如何重寫功能HEXTOINT,因爲它調用nibbleToInt功能的兩倍,它返回Maybe Int。我不知道如何測試這兩個值。

任何幫助是值得歡迎的,因爲我不知道我身邊的任何哈斯克爾程序員......

+0

適用的組成是你所需要的。在Hoogle中查找'liftA2'或'<*>'和'<$>'。 – Jubobs

+0

非常感謝您的回答! – ols

回答

3

可以使用Maybe單子鏈接在一起操作,如果值是Just只應發生的序列。如果該值是Nothing時,則鏈將停止:

hexToInt :: String -> Maybe Int 
hexToInt (x:y:[]) = do 
    a <- nibbleToInt x -- chain will end if nibbleToInt evaluates to Nothing 
    b <- nibbleToInt y -- chain will end if nibbleToInt evaluates to Nothing 
    return (a * 16 + b) -- chain completed successfully 
hexToInt _ = Nothing 

hexToInts :: String -> Maybe [Int] 
hexToInts [] = return [] 
hexToInts (n1:n2:ns) = do 
    i <- hexToInt (n1:[n2]) -- chain will end if hexToInt evaluates to Nothing 
    is <- hexToInts ns  -- chain will end if hexToInts evaluates to Nothing 
    return (i:is)   -- chain completed successfully 
hexToInts _ = Nothing 

你也可以使用Applicative風格,確實更實用的風格同樣的事情:

hexToInt :: String -> Maybe Int 
hexToInt (x:y:[]) = f <$> nibbleToInt x <*> nibbleToInt y where 
    f a b = a * 16 + b 
hexToInt _ = Nothing 

hexToInts :: String -> Maybe [Int] 
hexToInts [] = return [] 
hexToInts (n1:n2:ns) = (:) <$> hexToInt (n1:[n2]) <*> hexToInts ns 
hexToInts _ = Nothing 

注意hexToInts可以使用splitAt打破清單:

hexToInts :: String -> Maybe [Int] 
hexToInts [] = return [] 
hexToInts ns = (:) <$> hexToInt a <*> hexToInts as where 
    (a, as) = splitAt 2 ns 

或者寫一個幫助函數來配對列表中的元素和我們e mapM在配對上應用一元函數:

toPairs :: [a] -> [[a]] 
toPairs [] = [] 
toPairs xs = a : toPairs as where 
    (a, as) = splitAt 2 xs 

hexToInts :: String -> Maybe [Int] 
hexToInts = mapM hexToInt . toPairs