Haskell 从 URLType 中提取主机名

Haskell extract hostname from URLType

我正在使用 Network.URL 并从字符串导入 URL:

url_type $ fromJust $ importURL "https://google.com/"
Absolute (Host {protocol = HTTP True, host = "google.com", port = Nothing})

现在获取主机,我可以进行模式匹配并使用主机功能:

url' :: URLType -> Host
url' (Absolute host) = host

host $ url' $ url_type $ fromJust $ importURL "https://google.com"

那当然可以,但是 URL类型定义为:

data URLType
  = Absolute Host
  | HostRelative
  | PathRelative

url'函数中,只考虑了Absolute Host,如果url是HostRelativePathRelative就会失败。我怎样才能制作一个 url' 函数来提取主机,无论是否给定?

原回答

我想你所需要的只是让你的 url' 成为一个单子函数,它 return 是一个 Maybe Host,将 url_typereturn 组合成另一个单子函数return 是一个 Monad 的函数(在此特定用途中恰好也是一个 Maybe),然后使用 >>= 运算符创建一个单子链:

import Network.URL
import Data.Maybe (fromJust)

url' :: URLType -> Maybe Host
url' (Absolute host) = Just host
url' _ = Nothing

output :: Maybe Host
output = importURL "https://google.com" >>= return . url_type >>= url'

请注意 outputMaybe Host。如果您接受整个操作可能会失败,则无法获得 Host。如果您可以假设操作不会失败,那么您可以接受 fromJust,但我相信您会问这个问题,如果是这样的话。

改进

评论中指出>> return . url_type有点恶心。我是Haskell的新手,所以我基本上是第一个想到的就写了。可能我选择了 monadic 风格,因为我一直在研究和研究 monads 的例子,而不是应用程序。另外,我仍然是 Haskell 的新手,无法轻松地一起使用函数式、应用式和单子式样式:我只是没想过按照评论中的建议编写表达式,因为我的看起来不错。下面我根据我的知识“重新解释”评论。

有点难看的是 importURL "https://google.com" >>= return . url_type 部分,因为运算符 >>=,其类型通常为 Monad m => m a -> (a -> m b) -> m b,正在将其第二个参数“强制”为 return a Monad,即使“wannabe”第二个参数 url_type 没有,因此迫使我们将其与 return 组合,以尊重 a -> m b 部分签名。我们真正想要的是在 importURL "bla" 提供的 monad 中发送 url_type,在里面操作,并将结果留在那里,在 monad 中;也就是说,我们实际上只是将 importURL "bla" 用作 Functor(确实如此,因为它是 Monad)。那么我们该怎么做呢?我们通过 fmap:

来实现
output = (fmap url_type $ importURL "https://google.com") >>= url'

我不得不使用 $ 来防止 fmap 急切地吞下 importURL,从而留下字符串。我们还没有完成:fmap 有一个等价的中缀,<$>(注意 $<$> 彼此没有任何关系),所以我们可以重写以上为

output = url_type <$> importURL "https://google.com" >>= url'

在这一点上,我想说,我们有一个比以前更丑陋的表达式,输入在它的中间。但是 =<< 到resque。它本质上是 flip (>>=),所以我们可以翻转两个操作数,从而得到评论中建议的表达式:

output = url' =<< url_type <$> importURL "https://google.com"