Haskell 管道和分支

2023-11-27

Problem

我正在尝试使用 Haskell 和 Pipes 库实现一个简单的 Web 服务器。我现在明白循环或菱形拓扑对于管道是不可能的,但我认为我正在尝试这样做。我想要的拓扑结构是:

                                 -GET--> handleGET >-> packRequest >-> socketWriteD
                                 |
socketReadS >-> parseRequest >-routeRequest
                                 |
                                 -POST-> handlePOST >-> packRequest >-> socketWriteD

I have HTTPRequest RequestLine Headers Message and HTTPResponse StatusLine Headers Message链中使用的类型。socketReadS从套接字获取字节并将它们转发到parseRequest,它使用 Attoparsec 将字节解析为HTTPRequest目的。然后,我希望管道至少分支两次,甚至可能更多,具体取决于我实现的 HTTP 方法的数量。每个handle<method>函数应该接收HTTPRequest来自上游和前方的对象HTTPResponse反对packRequest,它只是将 HTTPResponse 对象打包在一个ByteString准备发送socketWriteS.

如果我让 GHC 推断类型,以下代码将进行类型检查routeRequest'''(我的似乎有点偏离)。然而之后似乎没有任何执行parseRequest。谁能帮我弄清楚为什么?

Code

我有以下代码routeRequest它应该处理分支。

routeRequest''' ::
    (Monad m, Proxy p1, Proxy p2, Proxy p3)
    => () -> Consumer p1 HTTPRequest (Pipe p2 HTTPRequest HTTPRequest (Pipe p3 HTTPRequest HTTPRequest m)) r
routeRequest''' () = runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ forever $ do
    httpReq <- request ()
    let method = getMethod httpReq
    let (URI uri) = getURI httpReq
    case method of
      GET -> lift $ respond httpReq
      POST -> lift $ lift $ respond httpReq

routeRequest'' = runProxyK $ routeRequest''' <-< unitU
routeRequest' socket = runProxyK $ raiseK (p4 socket <-< handleGET) <-< routeRequest''
routeRequest socket = (p4 socket <-< handlePOST) <-< (routeRequest' socket)

handleGET and handlePOST是这样实现的:

handleGET :: Proxy p => () -> p () HTTPRequest r ByteString IO r
handleGET () = runIdentityP $ do
    httpReq <- request ()
    let (URI uri) = getURI httpReq
    lift $ Prelude.putStrLn "GET"
    respond $ B.append (B.pack "GET ") uri


handlePOST :: Proxy p => () -> p () HTTPRequest r ByteString IO r
handlePOST () = runIdentityP $ do
    httpReq <- request ()
    let (URI uri) = getURI httpReq
    lift $ Prelude.putStrLn "POST"
    respond $ B.append (B.pack "POST ") uri

我对代理有以下简写:

p1 socket = socketReadS 32 socket
p2 = parseRequestProxy 
p4 socket = socketWriteD socket

最后,我像这样运行整个过程:

main = serveFork (Host "127.0.0.1") "8080" $
    \(socket, remoteAddr) -> do
        ret <- runProxy $ runEitherK $ p1 socket >-> printD >-> p2 >-> printD  >-> routeRequest socket 
        Prelude.putStrLn $ show ret

的类型签名parseRequestProxy这是:

parseRequestProxy
  :: (Monad m, Proxy p) =>
     ()
     -> Pipe
          (EitherP Control.Proxy.Attoparsec.Types.BadInput p)
          ByteString
          HTTPRequest
          m
          r

Edit

这是包含源代码的存储库。请注意,它尚未经过美化,因此使用风险需您自担。https://bitbucket.org/Dwilson1234/haskell-web-server/overview


当我最初说你无法处理菱形拓扑时,我错了。后来我发现了一种明智的方法来做到这一点ArrowChoice类似的界面并将解决方案包含在pipes-3.2.0的形式leftD and rightD组合器。我将解释它是如何工作的:

您可以用一个包装结果,而不是嵌套代理变压器Left or Right

routeRequest ::
    (Monad m, Proxy p)
    => () -> Pipe p HTTPRequest (Either HTTPRequest HTTPRequest) m r
routeRequest () = runIdentityP $ forever $ do
    httpReq <- request ()
    let method = getMethod httpReq
    let (URI uri) = getURI httpReq
    respond $ case method of
      GET  -> Left  httpReq
      POST -> Right httpReq

然后您可以有选择地将每个处理程序应用到每个分支,然后合并分支:

routeRequest >-> leftD handleGET >-> rightD handlePOST >-> mapD (either id id)
    :: (Monad m, Proxy p) => () -> Pipe p HTTPRequest ByteString IO r

如果你有两个以上的分支,那么你将不得不嵌套Eithers,但这只是限制ArrowChoice works.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 管道和分支 的相关文章

  • 在 Haskell 中等待然后检测按键的简单方法是什么?

    我对 Haskell 还很陌生 所以我正在寻找一种简单的方法来检测按键 而不是使用getLine 如果有人知道任何库 或者知道一些这样做的技巧 那就太好了 如果有更好的地方可以问这个问题 请直接告诉我 我将不胜感激 如果您不想阻止 可以使用
  • 在生成此 SOP 函数时,如何修复类型错误,包括“无法对 Traversable 进行量化”?

    我只是说我什至不确定这是否可能 这是迄今为止我在 Haskell 中尝试过的最通用的事情 我正在尝试制作一个更通用的版本applyFunc在发现https stackoverflow com a 58890226 3096687 https
  • 使用 Haskell 的欧拉项目 #1

    import Data Set euler Int euler sum x x lt nums where nums Data Set toList Data Set union Data Set fromList 3 6 999 Data
  • 副作用是纯函数中找不到的一切吗?

    可以肯定地说 以下二分法成立 每个给定的函数是 要么纯粹 或有副作用 如果是这样 函数的 副作用就是纯函数中找不到的任何东西 这很大程度上取决于您选择的定义 可以公平地说 函数是pure or impure 纯函数始终返回相同的结果并且不会
  • Haskell,范围缩小到无步骤[重复]

    这个问题在这里已经有答案了 为什么在 Haskell 中工作范围不能降低到没有步骤 7 1 gt 但只工作这个 7 6 1 gt 7 6 5 4 3 2 1 Haskell 无法知道您想要执行 1 除非您给出提示 在某些情况下 您可能需要一
  • 算法 - 如何有效删除列表中的重复元素?

    有一个list L 它包含以下元素任意类型each 如何有效删除此类列表中的所有重复元素 必须保留订单 只需要一个算法 因此不允许导入任何外部库 相关问题 在Python中 从列表中删除重复项以使所有元素都是唯一的最快算法是什么在维持秩序的
  • Haskell 二进制解析

    我一直在尝试在 haskell 中实现一个协议解析器 而且我对这门语言还很陌生 特别是当涉及到 monad 时 我一直在使用binary 0 5 0 2 并描述了协议的标头和所有有效负载 我想要解析的消息如下所示 header payloa
  • 如何、为什么以及何时使用“.Internal”模块模式?

    我在上面看到了几个包裹hackage http hackage haskell org packages archive pkg list html其中包含模块名称 Internal作为他们的姓氏组成部分 例如Data ByteString
  • 如何获取常量内存中的统计数据

    我有一个函数 它会创建一些随机的数值结果 我知道 结果将是 a 小 a b 约 50 范围内的整数a b 我想创建一个执行上述函数 1000000 次的函数 并计算每个结果出现的频率 该函数使用随机生成器来生成结果 问题是 我不知道如何在常
  • GHC 是否使用存在类型的动态调度?

    下面的代码是否使用了 C 或 Java 中所理解的动态调度 据我了解 在最后一行 编译器不可能在编译时知道要调用哪个 实现 但代码会编译并产生正确的结果 有人可以解释一下 这背后有什么样的实现 例如 vptr 吗 LANGUAGE Exis
  • 在 haskell 中处理 IO 与纯代码

    我正在编写一个shell脚本 我在haskell中的第一个非示例 它应该列出一个目录 获取每个文件大小 进行一些字符串操作 纯代码 然后重命名一些文件 我不确定我做错了什么 所以有两个问题 我应该如何安排这样的程序中的代码 我有一个具体问题
  • 对元组列表进行排序的函数 - Haskell

    抱歉 这个简单的问题只是我对 haskell 非常陌生 我正在尝试编写一个函数 order 它将对另一个函数 Frequency 生成的元组列表进行排序 频率计算列表中不同元素的数量 a给出一个这样的结果 比如 gt 频率 aabbbccc
  • 有什么方法可以在 do / while / let 块中打印出变量的类型吗?

    有没有办法打印出嵌套变量的推断类型ghci 考虑代码 let f g where g x Int x 那么 最好查询一下类型g e g t f g会打印出Int gt Int 您可以通过给出适当的错误类型注释并检查错误消息来诱骗此信息 Ma
  • 管道中缺少 ResourceT 实例

    我在尝试使用时遇到奇怪的错误ResourceT http hackage haskell org package conduit 1 0 9 1 docs Data Conduit html t 3aResourceT来自管道 1 0 9
  • 地图不是接受一个函数而列表返回一个列表吗?

    map2 List a gt b gt c gt a gt b gt c map2 List f map2 List f a as bs map f a bs map2 List f as bs 这是我的讲座中的一个示例 它尝试将二元函数应
  • 如何避免编写这种类型的 Haskell 样板代码

    我经常遇到这种情况 这很烦人 假设我有一个 sum 类型 它可以保存一个实例x或一堆其他无关的事情x data Foo x X x Y Int Z String other constructors not involving x 要声明
  • 如何使用 Haskell 提交 html 表单

    我知道如何使用http 管道 http hackage haskell org package http conduit 2 1 0包的 simplehttp 从 URL 检索页面 现在如果那样的话怎么办 网页有一个输入文本字段和一个提交按
  • 为什么以下内容会并行运行而不是顺序运行?

    给定以下函数evalPair parPair and deepSeq分别 evalPair Strategy a gt Strategy b gt Strategy a b evalPair sa sb a b do a lt sa a b
  • 数据类型变体之间的转换

    假设我想创建一种数据类型的两种变体 一种具有特定的构造函数 另一种没有它 否则它们是相同的 我想出了这个 LANGUAGE KindSignatures LANGUAGE DataKinds LANGUAGE GADTs data Foo
  • Haskell 中的所有图形和 Web 库是如何实现的?

    我才开始学习Haskell 我读到它是一种纯函数式语言 其中的所有内容都是不可变的 因此 输入输出 写入和读取数据库之类的事情会导致状态的可变性 我知道 Haskell 中有一种叫做 monad 的东西 它允许在 Haskell 中使用命令

随机推荐

  • 如何使用 Ruby 1.9 转换字符编码

    我目前在处理 Amazon API 的结果时遇到问题 该服务返回一个带有 unicode 字符的字符串 在 Mac 上学习 Objective xE2 x80 x93C 学习系列 在 Ruby 1 9 1 中 字符串甚至无法被处理 REXM
  • 预加载背景图片

    有大量关于如何预加载图像的文章 但是我似乎找不到任何关于使用 jquery 预加载背景图像的有用信息 我制作了一个简单的 html 模型来实现我想要实现的目标 http jsfiddle net 3rfhr 出现加载 div 背景已加载 加
  • 无法通过在 web.config 中添加 appcontext 设置来将应用程序设置为使用系统默认 TLS 版本

    根据 net 的指导TLS协议编程 当您的项目面向 net 4 6 时 它建议通过 appcontext 开关配置安全性 当在控制台应用程序的 app config 中添加 appcontext 时 这种方法有效 但是 在网站项目的 web
  • 设置SeekBar的宽度以实现“滑动解锁”效果

    我正在尝试使用 SeekBar 进行滑动解锁功能 我想要的外观如下所示 它由两个图像 一个背景和一个按钮组成 我将背景和 SeekBar 都放在 FrameLayout 中 以便 SeekBar 应该位于背景之上 Like so
  • Google 地图中的灰色区域

    我已经在我的应用程序中 以模式 实现了谷歌地图 但是正如您在下面的图像中看到的那样 有一个我当然想要摆脱的灰色区域 可以移动地图以使灰色区域消失 但这不是必需的 问题是 地图显示在模式框内 其中包含单击用于显示模式的按钮时动态创建的大量内容
  • 重写继承方法时避免显式类型转换

    我有一个基抽象类 它也实现了特定的接口 public interface IMovable
  • 准备弃用 std::iterator

    On March 21st the standards committee voted to approve the deprecation of std iterator proposed in P0174 对于读者来说 一长串的 voi
  • Python 写入文件返回空文件

    我正在尝试执行简单的命令将 hello world 写入文件 Python 2 7 3 default Feb 11 2013 12 48 32 GCC 4 4 6 20120305 Red Hat 4 4 6 4 on linux2 Ty
  • 如何在 Bootstrap 中将 YouTube 嵌入视频居中对齐

    我正在尝试将 YouTube 嵌入视频对齐到引导页面的页面中心 视频的大小始终相同 我的 html 看起来非常简单 div class video div 我尝试了 stackoverflow 中的不同解决方案 它只解决了将 div 居中
  • 运行 concat/uglify 后出现 Angular“状态已定义”错误

    我正在开发一个 AngularJS 应用程序 为了将代码交付到生产环境中 我使用了这个 Grunt 配置 任务 grunt registerTask compile sass compile copy compile assets ngAn
  • 使用 xelatex 进行 Rmarkdown

    我正在尝试使用 Calibri 字体 但据我了解 我首先需要能够使用 xelatex 引擎 这就是我遇到问题的地方 示例代码和错误如下 请注意 我对乳胶很陌生 所以我很可能错过了一些明显的东西 如果重要的话 我安装了 MikTeX 2 9
  • 我可以覆盖 std::hash 吗?

    我可以替换实际的实现std hash用我自己的定义std hash在 C 11 中 我的意思是来自我的代码库 而不触及标准库 在这种情况下 我看不到虚拟函数 多态性有任何用处 所以我想我无论如何都无法改变 std hash 的定义 您可以将
  • 避免 DELETE 查询中的自引用

    我正在尝试删除其名称下不是最新版本的所有记录 但显然您无法引用访问您在同一查询中修改的表 我尝试了这个 但由于上述原因它不起作用 DELETE FROM table WHERE CONCAT name version NOT IN SELE
  • 使用java加密和解密密码使用什么API和算法

    我目前正在使用 Java 创建应用程序 我在 google 上搜索了 java 密码加密 但结果如此巨大 我感到不知所措 如何使用 Java 加密和解密密码 加密和解密密码的最佳实践是什么 我猜 MD5 不是一种可行的方法 因为它是一种单向
  • 如何从包含多个 GzipStream 的文件中读取

    我有一个使用代码创建的文件 如下所示 using var fs File OpenWrite tmp using GZipStream gs new GZipStream fs CompressionMode Compress true u
  • package code.google.com/p/go.example/hello: exec: "hg": 在 %PATH% 中找不到可执行文件。如何获取远程golang包?

    我按照 Golang 教程中写的那样做http golang org doc code html remote 我的环境设置 C sbox go example gt set go GOPATH C sbox go example GORO
  • Android OpenGL ES Framebuffer 对象 - 将深度缓冲区渲染到纹理

    我使用的 Android 设备运行 Froyo 支持 OpenGL ES 1 1 和 OpenGL ES 2 0 我想将深度缓冲区渲染为纹理 在看过其他平台 包括 iPhone 上的 OpenGL OpenGL ES 的许多示例后 我尝试了
  • AJAX 文件上传/表单提交无需 jquery 或 iframe?

    是否可以在没有 jQuery 或 IFrames 的情况下进行 AJAX 表单提交 因此只需纯 JavaScript 我目前正在发送到一个可以工作的struts fileUploadAction 该操作的代码是否仍适用于异步提交 或者是否需
  • 我可以在 iOS 上将 HTTP 缓存与 NSURLSessionDownloadTask 一起使用吗?

    我正在尝试使用NSURLSessionDownloadTask 并利用 Apple 内置的 URL 缓存功能 我已经成功地让缓存在使用时起作用NSURLSessionDataTask使用下面的代码 void downloadUsingNSU
  • Haskell 管道和分支

    Problem 我正在尝试使用 Haskell 和 Pipes 库实现一个简单的 Web 服务器 我现在明白循环或菱形拓扑对于管道是不可能的 但我认为我正在尝试这样做 我想要的拓扑结构是 GET gt handleGET gt gt pac