1

失敗する可能性のある関数があるため、関数が返す値を Maybe でラップする必要があります。これも失敗する可能性のある別の関数を使用しており、これも Maybe にラップされています。問題は、型を中間計算で機能させるために、Maybe コンテキストで機能するように関数を「時期尚早に」持ち上げる必要があることです。その結果、私が望むのは Maybe [Integer] であるのに、Maybe [Maybe Integer] という型を取得することになります。問題の関数は exptDecipherString 関数です。「時期尚早」なリフティングを強制する関数は、modularInverse 関数です。

import Data.Char
import Control.Applicative
import Control.Monad
import Math.NumberTheory.Powers

--Helpers

extendedGcd::Integer->Integer->(Integer, Integer)
extendedGcd a b | r == 0 = (0, 1)
                | otherwise = (y, x - (y * d))
                where
                    (d, r) = a `divMod` b
                    (x, y) = extendedGcd b r

modularInverse::Integer->Integer->Maybe Integer
modularInverse n b | relativelyPrime n b = Just . fst $ extGcd n b
                   | otherwise = Nothing
                   where
                        extGcd = extendedGcd

relativelyPrime::Integer->Integer->Bool
relativelyPrime m n = gcd m n == 1 

textToDigits::String->[Integer]
textToDigits = map (\x->toInteger (ord x - 97)) 

digitsToText::[Integer]->String
digitsToText = map (\x->chr (fromIntegral x + 97)) 

--Exponentiation Ciphers

exptEncipher::Integer->Integer->Integer->Maybe Integer
exptEncipher m k p | relativelyPrime k (m - 1) = Just $ powerMod p k m 
                   | otherwise = Nothing

exptDecipher::Integer->Integer->Integer->Maybe Integer
exptDecipher m q c | relativelyPrime q (m - 1) = Just $ powerMod c q m
                   | otherwise = Nothing

exptEncipherString::Integer->Integer->String->Maybe [Integer]
exptEncipherString m k p | relativelyPrime k (m - 1) = mapM (exptEncipher m k) plaintext
                         | otherwise = Nothing
    where
        plaintext = textToDigits p

exptDecipherString::Integer->Integer->[Integer]->Maybe String
exptDecipherString m k c | relativelyPrime k (m - 1) = fmap digitsToText plaintext
                         | otherwise = Nothing
    where
        q = modularInverse k (m - 1)
        plaintext = mapM (exptDecipher m <$> q <*>) (map pure c)
4

1 に答える 1

6

「X を Y にする方法」で通常最初に試すべきことはhoogleです。この場合、 2 つの を 1 つjoinに折りたたむを使用することをお勧めしますMaybe

いくつかのコードを再構築することで、Maybeモナドをここで使用することもできます。

他のすべてが失敗した場合は、関数またはパターン マッチングを使用した case ステートメントを使用する独自のソリューションを展開します。

于 2012-04-02T00:40:28.730 に答える