首页 > 解决方案 > Haskell - 如何将基于管道的 JSON 转换为数据记录?

问题描述

我正在构建一个强化学习库,我想通过管道 JSON 将某些实例信息传递到可执行文件中。

使用aeson's Simplest.hs,我可以让以下基本示例按预期工作。请注意,参数是Main.hs作为String params占位符的。

我试图修改Main.hs,所以我会通过管道从 JSON 文件中输入 Nim 游戏参数,getContents但我遇到了预期的问题。我试图尽可能多地阅读有关 IO 的信息,但无法弄清楚如何提升我的 JSON 解析方法来处理 IO。[Char]IO String

我将如何修改以下内容以便可以使用管道输入的 JSON?

主文件

module Main where

import qualified System.Random as Random

import qualified Data.ByteString.Lazy.Char8 as BL

import qualified Games.Engine as Engine
import qualified Games.IO.Nim as NimIO
import qualified Games.Rules.Nim as Nim
import qualified Games.Learn.ValueIteration as VI


main :: IO ()
main = do
    let params = "{\"players\":[\"Bob\", \"Alice\", \"Charlie\"], \"initialPiles\": [3, 4, 5], \"isMisere\": false}"
    let result = NimIO.decode $ BL.pack params :: Maybe NimIO.NimGame
    case result of
        Nothing -> putStrLn "Parameter errors."
        Just game -> do
            putStrLn "Let's play some Nim! Remainder of code omitted"

Games.IO.Nim.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Games.IO.Nim 
    ( decode
    , NimGame
    , players
    , initialPiles
    , isMisere
    ) where


import Control.Applicative (empty)
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Aeson
    ( pairs,
      (.:),
      object,
      FromJSON(parseJSON),
      Value(Object),
      KeyValue((.=)),
      ToJSON(toJSON, toEncoding),
      decode)


data NimGame = NimGame
    { players :: [String]
    , initialPiles :: [Int]
    , isMisere :: Bool
    } deriving (Show)


instance ToJSON NimGame where
    toJSON (NimGame playersV initialPilesV isMisereV) = object [ "players" .= playersV,
                                                                 "initialPiles" .= initialPilesV,
                                                                 "isMisere" .= isMisereV]
    toEncoding NimGame{..} = pairs $
        "players" .= players <>
        "initialPiles" .= initialPiles <>
        "isMisere" .= isMisere


instance FromJSON NimGame where
    parseJSON (Object v) = NimGame <$>
                           v .: "players" <*>
                           v .: "initialPiles" <*>
                           v .: "isMisere"
    parseJSON _          = empty

Main.hs产生编译错误的替代方案

module Main where

import qualified System.Random as Random

import qualified Data.ByteString.Lazy.Char8 as BL

import qualified Games.Engine as Engine
import qualified Games.IO.Nim as NimIO
import qualified Games.Rules.Nim as Nim
import qualified Games.Learn.ValueIteration as VI


main :: IO ()
main = do
    --let params = "{\"players\":[\"Bob\", \"Alice\", \"Charlie\"], \"initialPiles\": [3, 4, 5], \"isMisere\": false}"
    let params = getContents
    let result = NimIO.decode $ BL.pack params :: Maybe NimIO.NimGame
    case result of
        Nothing -> putStrLn "Parameter errors."
        Just game -> do
            putStrLn "Let's play some Nim!"

编译错误

(base) randm@pearljam ~/Projects/gameshs $ stack build
gameshs-0.1.0.0: unregistering (local file changes: app/Nim.hs)
gameshs> configure (lib + exe)
Configuring gameshs-0.1.0.0...
gameshs> build (lib + exe)
Preprocessing library for gameshs-0.1.0.0..
Building library for gameshs-0.1.0.0..
Preprocessing executable 'nim-exe' for gameshs-0.1.0.0..
Building executable 'nim-exe' for gameshs-0.1.0.0..
[2 of 2] Compiling Main

/home/randm/Projects/gameshs/app/Nim.hs:17:41: error:
    • Couldn't match expected type ‘[Char]’
                  with actual type ‘IO String’
    • In the first argument of ‘BL.pack’, namely ‘params’
      In the second argument of ‘($)’, namely ‘BL.pack params’
      In the expression:
          NimIO.decode $ BL.pack params :: Maybe NimIO.NimGame
   |
17 |     let result = NimIO.decode $ BL.pack params :: Maybe NimIO.NimGame
   |                                         ^^^^^^


--  While building package gameshs-0.1.0.0 (scroll up to its section to see the error) using:
      /home/randm/.stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.2.1.0_ghc-8.10.4 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0 build lib:gameshs exe:nim-exe --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

标签: jsonhaskell

解决方案


getContents返回的不是String您显然期望的 a ,而是IO String,它是一个“程序”,执行时将产生 a String。因此,当您尝试使用 解析此程序时decode,这当然行不通:decode解析 aString时,它无法解析程序。

那么如何执行这个程序来获取String? 有两种方法:要么让它成为另一个程序的一部分,要么调用它main,它成为你的入口点。

在您的情况下,明智的做法是成为getContent您的main程序的一部分。为此,请使用左箭头<-,如下所示:

main = do
    params <- getContents
    let result = NimIO.decode $ BL.pack params :: Maybe NimIO.NimGame
    ...

推荐阅读