2016-10-22 9 views
1

私はハスケルの初心者です。ハスケルでcryptopalsの暗号のチャレンジをしようとしています。たぶん値を確認する

私は、次のコードを書いた:

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 

しかし、その後、私はそれがMaybe Intを返す、二回nibbleToInt関数を呼び出すように、関数HEXTOINTを書き換える方法がわかりません。私はそれらの2つの値をテストする方法を知らない。私は私の周りに任意のHaskellのプログラマを知らないよう

すべてのヘルプは、大歓迎です...

+0

必要なものは次のとおりです。 Hoogleの 'liftA2'または' <*> 'と' <$> 'を検索してください。 – Jubobs

+0

お返事ありがとうございました! – ols

答えて

3

あなたは一緒にチェーンに値がJustある場合にのみ起こるべき一連の操作をMaybeモナドを使用することができます。値が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スタイル使用することができますhexToIntsが使用できる

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 

は注意をsplitAtリストを中断するには:

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

また、リストの要素をペアにするヘルパー関数を記述すると、

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

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