首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将IO (可能(IO (可能)降为IO (可能a)

将IO (可能(IO (可能)降为IO (可能a)
EN

Stack Overflow用户
提问于 2021-12-22 07:57:47
回答 2查看 139关注 0票数 3

我有一个函数,用HsOpenSsl的readPrivateKey函数读取Rsa键,不幸的是,我函数的签名是这个String -> IO (Maybe (IO Maybe RsaKey))。我需要PEM格式和一个Cryptonite.RSA键,我编写了函数mkRsaKey,通过一个PEM格式的字符串来实现它。

这是代码:

代码语言:javascript
复制
import qualified Crypto.PubKey.RSA as Rsa --from cryptonite
import OpenSSL.EVP.PKey -- from HsOpenSSL
import OpenSSL.PEM -- from HsOpenSSL
import OpenSSL.RSA -- from HsOpenSSL
import Prelude

data RsaKey = RsaKey
  { rsaKeyCryptoniteKey :: Rsa.PrivateKey,
    rsaKeyStringRepr :: String
  }
  deriving (Show)

openSslKeyToCryptoniteKey :: RSAKeyPair -> Maybe Rsa.PrivateKey
openSslKeyToCryptoniteKey key = do
  let d = rsaD key
  let p = rsaP key
  let q = rsaQ key
  let mdP = rsaDMP1 key
  let mdQ = rsaDMQ1 key
  let mqinv = rsaIQMP key
  let size = rsaSize key
  let n = rsaN key
  let e = rsaE key
  dP <- mdP
  dQ <- mdQ
  qinv <- mqinv

  let pub = Rsa.PublicKey size n e
  return $ Rsa.PrivateKey pub d p q dP dQ qinv

openSslKeyToRsaKey :: RSAKeyPair -> IO (Maybe RsaKey)
openSslKeyToRsaKey key = do
  stringRepr <- writePublicKey key
  let maybeCryptoKey = openSslKeyToCryptoniteKey key
  return $ do
    cryptoKey <- maybeCryptoKey
    return $ RsaKey cryptoKey stringRepr

mkRsaKey :: String -> IO (Maybe (IO (Maybe RsaKey)))
mkRsaKey privateKey = do
  someOpenSslKey <- readPrivateKey privateKey PwNone
  let openSslKey = toKeyPair someOpenSslKey
  return $ openSslKeyToRsaKey <$> openSslKey

现在,正如您所看到的,在我的意义上,类型签名不是最优的,我希望有IO (Maybe RsaKey)。我怎样才能做到这一点?

编辑:

我确实做到了,但我用的是unsafePerformIO

代码语言:javascript
复制
mkRsaKey :: String -> IO (Maybe RsaKey)
mkRsaKey privateKey = do
  someOpenSslKey <- readPrivateKey privateKey PwNone
  return $ do
    openSslKey <- toKeyPair someOpenSslKey
    unsafePerformIO (openSslKeyToRsaKey $ openSslKey)

据我所知,您不应该使用unsafePerformIO,在没有它的情况下,有什么方法可以做到这一点吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-12-22 09:12:01

case发现得很好。这绝对不是你应该使用unsafePerformIO的地方。这里有一个更紧凑的方式,为了好玩。

代码语言:javascript
复制
flattenMaybe :: (Monad m) => m (Maybe (m (Maybe a))) -> m (Maybe a)
flattenMaybe m = m >>= fromMaybe (return Nothing)

为了更多的乐趣,像这样扁平层的能力是monads特有的能力;我们只是在m (Maybe ...)上使用这种能力,也就是MaybeT。所以我们也可以这样写:

代码语言:javascript
复制
flattenMaybe = runMaybeT . join . fmap MaybeT . MaybeT

执行必要的包装/展开操作以使用join at MaybeT m (MaybeT m a) -> MaybeT m a

票数 5
EN

Stack Overflow用户

发布于 2021-12-22 08:21:37

找到了一种不使用unsafePerformIO的方法,诀窍是使用一个case语句,该语句仅在Nothing情况下使用返回函数。以下是实现:

代码语言:javascript
复制
mkRsaKey :: String -> IO (Maybe RsaKey)
mkRsaKey privateKey = do
  someOpenSslKey <- readPrivateKey privateKey PwNone
  let maybeOpenSslKey = toKeyPair someOpenSslKey
  case maybeOpenSslKey of
    Just key -> openSslKeyToRsaKey key
    Nothing -> return Nothing
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70445844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档