dimid
dimid

Reputation: 7631

String vs Char mismatch in haskell

I'm getting an error about a type mismatch:

Main.hs:47:28:
    Couldn't match type ‘[Char]’ with ‘Char’
    Expected type: IO Char
      Actual type: IO String
    In the first argument of ‘liftIO’, namely ‘prompt’
    In the second argument of ‘($)’, namely ‘liftIO prompt’

and struggling to understand why an IO Char is expected. Since prompt does type-check as IO String in line 46, and I thought, perhaps mistakenly, that liftIO would turn it to a String as suggested in this answer.

module Main where

import Syntax
import Parser
import Eval
import Pretty
import Counter

import Control.Monad
import Control.Monad.Trans
import System.Console.Haskeline
import Control.Monad.State

showStep :: (Int, Expr) -> IO ()
showStep (d, x) = putStrLn ((replicate d ' ') ++ "=> " ++ ppexpr x)

process :: Counter -> String -> InputT (StateT [String] IO) ()
process c line =
    if ((length line) > 0)
       then
        if (head line) /= '%'
            then do
                modify (++ [line])
                let res = parseExpr line
                case res of
                    Left err -> outputStrLn $ show err
                    Right ex -> do
                        let (out, ~steps) = runEval ex
                        --mapM_ showStep steps
                        out_ps1 c $ out2iout $ show out
        else do
                let iout = handle_cmd line
                out_ps1 c iout

    -- TODO: don't increment counter for empty lines
    else do
      outputStrLn ""

out2iout :: String -> IO String
out2iout s = return s

out_ps1 :: Counter -> IO String -> InputT (StateT [String] IO) ()
out_ps1 c iout = do
      --out <- liftIO iout
      let out_count = c 0
      let prompt = (getPrompt out_count iout) :: IO String
      outputStrLn $ liftIO prompt
      outputStrLn ""


getPrompt :: IO Int -> IO String -> IO String
getPrompt ion iout = do
    n <- ion
    out <- iout
    return $ "Out[" ++ (show n) ++ "]: " ++ out


handle_cmd :: String -> IO String
handle_cmd line = if line == "%hist"
                     then
                        evalStateT getHist []
                     else
                        return "unknown cmd"

joinHist :: IO [String] -> IO String
joinHist ixs = do
    xs <- ixs
    return $ unlines xs

getHist :: StateT [String] IO String
getHist = do
    hist <- lift get
    let hists = (zip [(1::Int)..] hist) :: [(Int, String)]
    return $ combineHist hists


combineHist :: [(Int, String)] -> String
combineHist hists = unlines $ map (\(i, h) -> show i ++ ": " ++ show h) hists

main :: IO ()
main = do
    c <- makeCounter
    repl c

repl :: Counter -> IO ()
repl c = evalStateT (runInputT defaultSettings(loop c)) []

loop :: Counter -> InputT (StateT [String] IO) ()
loop c = do
    minput <- getLineIO $ in_ps1 $ c
    case minput of
      Nothing -> return ()
      Just input -> process c input >> loop c

getLineIO :: (MonadException m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
    s <- liftIO ios
    getInputLine s

in_ps1 :: Counter -> IO String
in_ps1 c = do
    let ion = c 1
    n <- ion
    let s = "Untyped: In[" ++ (show n) ++ "]> "
    return s

More context can be found here.

Upvotes: 1

Views: 162

Answers (1)

Bakuriu
Bakuriu

Reputation: 101959

You are passing an IO action in place of a String to outputStrLn. You should instead do:

prompt <- liftIO $ getPrompt out_count iout
outputStrLn prompt

to obtain the String from the IO action, using liftIO and then passing this to outputStrLn.

Upvotes: 1

Related Questions