在Servant中的API端点内发出请求

mrl*_*lee 3 haskell servant

我正在尝试使用telegram-api构建Telegram机器人.到目前为止,我还没有遇到任何问题,因为我可以阅读测试以了解事情是如何工作的,但是在使用Servant构建webhook端点时我遇到了很多麻烦.总的想法是,当我Update从webhook 收到一个,我发回一个回复.

问题在于我的postWebhook代码,它希望收到一个Message但是收到一个IO Message.我认为这是因为Servant不希望我在该函数内部发出请求,因为我确实应该有类型EitherT ServantError IO (IO Message)(部分应用BotHandler)EitherT ServantError IO Message.

我还在学习Haskell,但我知道我不得不从IO monad中获取消息?更新BotAPI返回a Post '[JSON] (IO Message)给我这个:No instance for (Foldable IO) arising from a use of ‘serve’,这超出了我的初学者的知识,我可以看到摆弄类型只是将相同的问题移动到代码的不同部分.我只是不知道如何解决它.

以下是删除了敏感字符串的代码:

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators     #-}

module Main where

import           Control.Monad
import           Control.Monad.Trans.Either
import           Data.Proxy
import           Data.Text                  (Text, pack)
import           Network.Wai.Handler.Warp
import           Servant
import           Web.Telegram.API.Bot

reply :: Token -> Message -> Text -> IO Message
reply token msg response = do
  Right MessageResponse { message_result = m } <-
    sendMessage token $ SendMessageRequest chatId response (Just Markdown) Nothing Nothing Nothing
  return m
  where chatId = pack . show $ chat_id (chat msg)

type BotAPI = "webhook" :> ReqBody '[JSON] Update :> Post '[JSON] Message
type BotHandler a = EitherT ServantErr IO a

botApi :: Proxy BotAPI
botApi = Proxy

initWebhook :: Token -> IO Bool
initWebhook token = do
  Right SetWebhookResponse { webhook_result = w } <-
    setWebhook token $ Just "https://example.com/webhook"
  return w

postWebhook :: Token -> Update -> BotHandler (IO Message)
postWebhook token update = case message update of
  Just msg -> return $ reply token msg "Testing!"
  Nothing -> left err400

server :: Token -> Server BotAPI
server = postWebhook

main :: IO ()
main = do
  initWebhook token
  run port $ serve botApi (server token)
  where token = Token "<token>"
        port = 8080
Run Code Online (Sandbox Code Playgroud)

抱歉可能不是理想的Haskell代码.先感谢您 :)

jos*_*uan 5

你的错误是在

Just msg ? return $ reply token msg "Testing!"
Run Code Online (Sandbox Code Playgroud)

你是在

EitherT ServantErr IO Message
Run Code Online (Sandbox Code Playgroud)

monad但reply有类型

reply :: Token ? Message ? Text ? IO Message
Run Code Online (Sandbox Code Playgroud)

然后简单地将lift这个IO动作变成你的monad,它有效

postWebhook :: Token ? Update ? BotHandler Message
postWebhook token update = case message update of
  Just msg ? lift $ reply token msg "Testing!"
  Nothing  ? left err400
Run Code Online (Sandbox Code Playgroud)

(不容易我解释一下这里所涉及的所有的东西),我想你应该多练习大约单子,变压器,...之前这些复杂的例子,但你勇敢!:)