繁体   English   中英

Haskell中的函数组成和类型注释

[英]Function composition and type annotations in Haskell

总菜鸟在这里。 我已经看到了使用do块执行HTTP Get请求的示例,但是我想通过组合来完成。

像这样:

get url = getResponseBody . simpleHTTP $ getRequest url

合适吗 对于此功能,正确的类型注释是什么?

可以的

get :: String -> IO String
get url = getResponseBody =<< simpleHTTP (getRequest url)

但是我想组成而不是绑定。 有什么更好/正确的方法?

如果我们查看类型:

getRequest :: String -> Request_String
simpleHTTP :: Request ty -> IO (Result (Response ty))
getResponseBody :: Result (Response ty) -> IO ty
type Request_String = Request String

因此,出于这个问题的目的,我们可以将类型专门化为

simpleHTTP :: Request_String -> IO (Result (Response String))
getResponseBody :: Result (Response String) -> IO String

很明显,我们可以做到

simpleHTTP (getRequest url) :: IO (Result (Response String))

但是,为了与getResponseBody进行组合,我们需要使用monadic组合器。 出于各种数学原因,但为简单起见,仅将其视为函数组合的功能不足以仅将函数组合在一起。 为了合成动作,引入了monad,它们带有自己的合成运算符。 比较这两个合成运算符的类型:

(.)   ::            (b ->   c) -> (a ->   b) -> (a ->   c)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)  -- Imported from Control.Monad

它们非常相似,不是吗? 唯一的区别是将mMonad约束相加。 这是monad 合成运算符,它比普通的更具限制性和强大. 运算符,这意味着它可以执行更多操作,例如排序和执行IO操作,但也意味着它可以使用更少的类型。 可以用作

get = simpleHTTP <=< simpleHTTP . getRequest

但是,在Control.Category中定义了一个更通用的组合版本,可以处理以下两个方面:

import Prelude hiding ((.), id)  -- Hide the less general versions in Prelude
import Control.Category
import Control.Arrow

get = runKleisli (Kleisli getResponseBody . Kleisli simpleHTTP) . getRequest

但这要求您将Kleisli函数包装在Kleisli包装器中,并用runKleisli对其进行runKleisli 您也可以跳过Control.Category而只需使用Control.Arrow

get = runKleisli (Kleisli getResponseBody <<< Kleisli simpleHTTP) <<< getRequest

您甚至可以将其交换为

get = getRequest >>> runKleisli (Kleisli simpleHTTP >>> Kleisli getResponseBody)

如果您希望它从左到右而不是从右到左阅读。

最后,有几种方法可以编写等效的代码,但是,如果您坚持使用无点样式(不必惯用),那么大多数人最熟悉和可读的方法就是使用通常的代码. <=<因为这是最短的实现,并且使用了更多可识别的运算符。 在构建自定义内容时, Control.CategoryControl.Arrow非常有用,但是对于内置类型,通常已经定义了更有意义的运算符。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM