gpt4 book ai didi

haskell - 在单子(monad)变压器类型类中使用列表单子(monad)?

转载 作者:行者123 更新时间:2023-12-04 15:11:06 32 4
gpt4 key购买 nike

我的目标是创建一个函数,该函数在 ReaderT WriterT 堆栈或 RWS 堆栈中使用 list monad。更一般地说,我如何在 mtl 类型类(如 MonadReader、MonadWriter)中使用列表 monad?

我为什么要这样做?这个问题是 Beginning Haskell 中的一个练习.它要求我“使用 MonadReader 和 MonadWriter 包装基本列表 monad 的功能。要检查该功能是否通用,请使用两个不同的 monad 来 [测试] 请求的功能:ReaderT r (WriterT w []) aRWST r w s m a”所以这本书暗示这个有可能。

我不知道如何“告诉”编译器使用列表单子(monad)。如果我使用 ask >>= liftask >>= lift . lift我可以让 2 级堆栈 ( RWST [] ) 或 3 级堆栈 ( ReaderT WriterT [] ) 工作,但不能同时工作。

我的问题的重点:

pathImplicitStack' start end | start == end = tell [end]
pathImplicitStack' start end =
do (s0, e0) <- ask >>= lift
guard $ s0 == start
tell [start]
pathImplicitStack' e0 end

另外,我想知道如何键入函数。到目前为止,我最好的尝试看起来像 pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m ()我知道这是不对的,可能缺少列表单子(monad)。另外,我认为 MonadPlus 可能在类型签名中很有用,但我不太确定。

此行: do (s0, e0) <- ask >>= lift是给我带来麻烦的人。我尝试了 0、1 和 2 次升降机,但均未成功。我想 ask对于 [(Int, Int)]然后使用 list monad 只处理 (Int, Int) (让列表单子(monad)为我尝试所有可能性)。

作为练习的一部分,我需要能够调用 pathImplicitStack'具有这两个功能(或非常相似的功能):
pathImplicitRW :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRW edges start end = execWriterT rdr
where rdr = runReaderT (pathImplicitStack' start end) edges :: WriterT [Int] [] ()

pathImplicitRWS :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRWS edges start end = map snd exec
where exec = execRWST (pathImplicitStack' start end) edges ()

这与我之前的问题有关: How do I use list monad inside of ReaderT?

整个文件便于测试:
{-# LANGUAGE FlexibleContexts #-}

module Foo where

import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.RWS

graph1 :: [(Int, Int)]
graph1 = [(2013,501),(2013,1004),(501,2558),(1004,2558)]


pathImplicitRW :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRW edges start end = execWriterT rdr
where rdr = runReaderT (pathImplicitStack' start end) edges :: WriterT [Int] [] ()

pathImplicitRWS :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRWS edges start end = map snd exec
where exec = execRWST (pathImplicitStack' start end) edges ()

pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> [m ()]
pathImplicitStack' start end | start == end = tell [end]
pathImplicitStack' start end =
do (s0, e0) <- ask >>= lift
guard $ s0 == start
tell [start]
pathImplicitStack' e0 end

编辑

根据 John L 的反馈,我尝试了
pathImplicitStack' :: (MonadReader [(Int, Int)] (t []), MonadWriter [Int] (t []), MonadPlus (t []), MonadTrans t) => Int -> Int -> t [] ()
pathImplicitStack' start end | start == end = tell [end]
pathImplicitStack' start end =
do (s0, e0) <- ask >>= lift
guard $ s0 == start
tell [start]
pathImplicitStack' e0 end

但正如他所指出的,它只能与一个 monad 转换器一起使用来包装列表 monad,即 RSWT,并且不能与 ReaderT WriterT 一起使用。所以这不是我正在寻找的解决方案。

最佳答案

因此,在问题的要求范围内这样做的基本问题是没有 MTL 库函数可以从可能是任意级别的列表 monad 中提升。但是,您可以“作弊”:MonadPlus组合 Monad 的实例无论深度如何,都从底层列表 monad 继承,您可以使用它来生成所需的操作:

  do  (s0, e0) <- ask >>= msum . map return

那么类型签名也有错误,需要改成:
pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m ()

编辑:实际上在第二个想法这实际上并不是作弊。它只是使用 MonadPlus用于链接替代操作的 API,而不是直接使用底层列表 monad。

关于haskell - 在单子(monad)变压器类型类中使用列表单子(monad)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24195617/

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