gpt4 book ai didi

haskell - 请更正我对 Maybe Monad 的使用

转载 作者:行者123 更新时间:2023-12-02 00:23:20 30 4
gpt4 key购买 nike

我正在实现一个执行求幂密码的小程序。一些计算可能会失败,例如,计算模逆。我已经使用 Maybe 来处理这些类型的失败。但是现在我被卡住了,因为我需要将 maybe 中的值“注入(inject)”到另一个部分应用的函数中。我知道如果我有一个接受一个参数的函数,我会使用 bind 来执行此操作。

import Data.Char
import Math.NumberTheory.Powers

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 = True
| otherwise = False

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

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

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

exptDecipher::Integer->Integer->Integer->Integer
exptDecipher m q c = powerMod c q m

exptEncipherString::Integer->Integer->String->[Maybe Integer]
exptEncipherString m k p = map (exptEncipher m k) plaintext
where
plaintext = textToDigits p

exptDecipherString::Integer->Integer->[Maybe Integer]->Maybe String
exptDecipherString m k c = (fmap digitsToText) plaintext
where
q = modularInverse k (m - 1)
plaintext = map (fmap $ exptDecipher m q) c

具体来说,我的问题出在函数 exptDecipherString 中,我需要将 q 中的 monad 封装的值注入(inject)到函数 exptDecipher 中,然后我将提升它以在 c 上工作。这样做的正确方法是什么?另外,我担心我最终会得到一个 [Maybe Char] 列表,而不是我想要的 Maybe String。我在推理所有这些时遇到了问题。谁能赐教一下?

最佳答案

您可以使用 sequence ap 得到类型的工作。首先是他们的签名:

ap :: Monad m => m (a -> b) -> m a -> m b
sequence :: Monad m => [m a] -> m [a]

注意 sequence直接解决您对 [Maybe Char] 的担忧而不是 Maybe String .两者都在 Control.Monad (请注意,您必须导入 ap )。我们可以按如下方式使用它们:

exptDecipherString :: Integer -> Integer -> [Maybe Integer] -> Maybe String
exptDecipherString m k c = fmap digitsToText plaintext
where
q = modularInverse k (m - 1)
plaintext = sequence $ map (ap $ fmap (exptDecipher m) q) c

我们可以通过研究类型来达到这一点。首先申请exptDecipherm ,它给了我们一个 Integer -> Integer -> Integer 类型的函数.我们想将其应用于 q , 但它是 Maybe Integer , 所以我们必须使用 fmap (exptDecipher m) q , 其类型为 Maybe (Integer -> Integer) .然后我们可以弹出 ap在前面并获得类型的东西 Maybe Integer -> Maybe Integer .然后我们将其映射到 c ,这给了我们一个 [Maybe Integer] ,我们可以使用 sequence 将其翻转过来.

这可能行不通——如果逻辑中存在错误等——但至少它可以编译。

一些旁注:您可以使用中缀运算符 <$><*>来自 Control.Applicative代替 fmapap ,分别用于稍微好一点的语法,以及你的 relativelyPrime可以更简单地写成 relativelyPrime m n = gcd m n == 1 .

关于haskell - 请更正我对 Maybe Monad 的使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9960224/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com