1
我有一個函數可能會失敗,所以它返回的值需要包裝在一個Maybe中。它使用另一個也可能失敗的函數,這也包含在Maybe中。問題是,爲了讓類型在中間計算中得到解決,我必須「提前」提升函數以在Maybe語境中工作。這導致我得到一個類型Maybe [也許整數],當我想要的是可能[整數]。有問題的函數是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)
我試過Hoogle,也許我對如何使用它很無聊。我輸入了「Monad m => m m a-> m a」或類似的內容。我仍然試圖找出如何考慮類型:( – 2012-04-02 02:27:30
@JoshInfiesto你的查詢幾乎是正確的!你忘記了一些括號,嘗試'Monad m => m(ma) - > ma',然後想想 – 2012-04-02 02:45:48
哎呦......類型構造函數關聯了左邊,難道他們不是...... – 2012-04-02 02:54:14