0

I'm building a reinforcement learning library where I'd like to pass certain instance information into the executables via a piped JSON.

Using aeson's Simplest.hs, I'm able to get the following basic example working as intended. Note that the parameters are sitting in Main.hs as a String params as a placeholder.

I tried to modify Main.hs so I would pipe the Nim game parameters in from a JSON file via getContents, but am running into the expected [Char] vs. IO String issue. I've tried to read up as much as possible about IO, but can't figure out how to lift my JSON parsing method to deal with IO.

How would I modify the below so that I can work with piped-in JSON?

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 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

Alternative Main.hs that generates compile error

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!"

Compile Error

(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
2
  • If your problem involves an error of some sort, it is usually a good idea to post the full text of the error, so that people answering your question don't have to guess. Commented Jun 8, 2021 at 0:15
  • Added alternative code and compiler error it generates. Commented Jun 8, 2021 at 0:19

1 Answer 1

1

getContents returns not a String as you apparently expect, but IO String, which is a "program", which, when executed, will produce a String. So when you're trying to parse this program with decode, of course that doesn't work: decode parses a String, it cannot parse a program.

So how do you execute this program to obtain the String? There are two ways: either you make it part of another program or you call it main and it becomes your entry point.

In your case, the sensible thing to do would be to make getContent part of your main program. To do that, use the left arrow <-, like this:

main = do
    params <- getContents
    let result = NimIO.decode $ BL.pack params :: Maybe NimIO.NimGame
    ...
Sign up to request clarification or add additional context in comments.

1 Comment

This works perfectly, thank you. Loving Haskell ... have implemented my Python library into Haskell with ~1/4 the code and 10x performance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.