2012-04-02 4 views
1

У меня есть функция, которая может выйти из строя, поэтому возвращаемое значение должно быть завершено в Maybe. Он использует другую функцию, которая также может потерпеть неудачу, и это также завернуто в Maybe. Проблема заключается в том, чтобы заставить типы работать в промежуточном вычислении, я должен «преждевременно» поднять функцию для работы в контексте Maybe. Это приводит к тому, что я получаю тип Maybe [Maybe Integer], когда я хочу, может быть, [Integer]. Эта функция является функцией exptDecipherString, функция, которая вызывает «преждевременный» подъем, является модульной инверсной функцией.Как избавиться от лишнего Может быть

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) 

ответ

6

Первое, что вы обычно должны попробовать «Как X может стать Y» является hoogle. В этом случае рекомендуется использовать join, что приведет к обрушению двух Maybe s в один.

С некоторой реструктуризацией кода, монада Maybe также может быть использована для вас.

Когда все остальное терпит неудачу, сверните свое собственное решение, которое использует функции или оператор case с соответствием шаблону.

+0

Я пробовал Hoogle, может быть, я не знаю, как его использовать. Я набрал «Monad m => m m a-> m a» или что-то в этом роде. Я все еще пытаюсь понять, как мыслить в типах :( –

+3

@JoshInfiesto Ваш запрос почти прав! Вы только что забыли некоторые круглые скобки. Попробуйте 'Monad m => m (ma) -> ma' вместо этого, а затем подумайте о том, почему этот запрос работает. –

+0

Упс ... Конструкторы типов ассоциируют левые, не так ли ... –

Смежные вопросы