2012-04-02 9 views
1

Ich habe eine Funktion, die möglicherweise fehlschlagen, so dass der Wert, den es zurückgibt, in ein Maybe gewickelt werden muss. Es verwendet eine andere Funktion, die ebenfalls fehlschlagen kann und die auch in eine Maybe eingeschlossen ist. Das Problem ist, um die Typen in einer Zwischenrechnung zu berechnen, muss ich eine Funktion "vorzeitig" anheben, um im Maybe-Kontext zu arbeiten. Das führt dazu, dass ich einen Typ bekomme. Vielleicht [Vielleicht Integer], wenn das, was ich will, vielleicht [Integer] ist. Die fragliche Funktion ist die exptDecipherString-Funktion, die Funktion, die "vorzeitiges" Heben erzwingt, ist die modularInverse-Funktion.Wie man ein Extra loswerden kann Vielleicht

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) 

Antwort

6

Das erste, was Sie in der Regel für versuchen sollten, „Wie kann X werden Y“ hoogle. In diesem Fall empfiehlt es sich, join zu verwenden, wodurch zwei Maybe s in eins zusammenfallen.

Mit einigen Code-Umstrukturierung, die Maybe Monad könnte auch verwendet werden, um Ihnen hier zu helfen.

Wenn alles andere fehlschlägt, rollen Sie Ihre eigene Lösung, die Funktionen oder eine Case-Anweisung mit Mustererkennung verwendet.

+0

Ich habe versucht, Hoogle, vielleicht bin ich dumm darüber, wie man es benutzt. Ich tippte "Monad m => m m a-> m a" oder etwas in diesem Sinne ein. Ich versuche immer noch herauszufinden, wie man in Typen denkt :( –

+3

@JoshInfiesto Ihre Frage ist fast richtig! Sie haben gerade einige Klammern vergessen. Versuchen Sie stattdessen 'Monad m => m (ma) -> ma', dann denken Sie nach warum diese Abfrage funktioniert –

+0

Whoops ... Typ Konstruktoren assoziieren links, nicht sie ... –

Verwandte Themen