0

I have a code that reads files and parses using UU.Parsing lib that returns an abstract sintax tree and shows on the screen.

I received the error message "No instance for Show" in my functions originated in tokensParserToByteString and applyParser using parseIO (of UU.Parsing lib) and inherited signatures until main. I fixed the signatures but my problem is in the main function. I added the instance Show in the signature but I have the next compilation error:

No instance for (Show (IO J2s)) arising from a use of ‘main’
In the expression: main
When checking the type of the IO action ‘main’

The complete error message is:

$ cabal build
Building java2scala-1.0...
Preprocessing library java2scala-1.0...
In-place registering java2scala-1.0...
Preprocessing executable 'java2scala' for java2scala-1.0...
Preprocessing executable 'test' for java2scala-1.0...
[5 of 5] Compiling Main             ( test/Main.hs, dist/build/test/test-tmp/Main.o )

test/Main.hs:27:1:
    No instance for (Show (IO J2s)) arising from a use of ‘main’
    In the expression: main
    When checking the type of the IO action ‘main’

Some idea, about the problem?

Main module

{-# LANGUAGE FlexibleContexts #-}
module Main where

import UU.Parsing
...
import Content

main :: (Show (IO J2s)) => IO()
main = do f <- getLine
      let command = test f
      command

test :: (Show (IO J2s)) => String -> IO()
test "testparser" = testParser

Test module

{-# LANGUAGE FlexibleContexts #-}
module J2s.Parser.Test where

import Content
import J2s.Ast.Sintax
import J2s.Parser
import UU.Parsing
...

testParser :: (Show (IO J2s)) => IO()
testParser  = (runSafeIO $ runProxy $ runEitherK $
                contentsRecursive "path/of/my/tests" />/ handlerParser) :: (Show (IO J2s)) => IO()

Content module

{-# LANGUAGE FlexibleContexts #-}
module Content where

import Control.Monad(forM, liftM)
import System.Directory (doesDirectoryExist, getDirectoryContents)
import System.FilePath ((</>), splitExtension, splitFileName)
import J2s.Parser
import J2s.Ast.Sintax
import UU.Parsing

import Control.Monad (when, unless)
import Control.Proxy
import Control.Proxy.Safe hiding (readFileS)

import J2s.Scanner.Token
import Text.Show

import UU.Parsing


contentsRecursive
     :: (CheckP p)
     => FilePath -> () -> Producer (ExceptionP p) FilePath SafeIO ()
contentsRecursive path () = loop path
   where
     loop path = do
         contents path () //> \newPath -> do
             respond newPath
             isDir <- tryIO $ doesDirectoryExist newPath
             let isChild = not $ takeFileName newPath `elem` [".", ".."]
             when (isDir && isChild) $ loop newPath


applyParser :: (Proxy p, Show (IO J2s)) => String -> Consumer p B.ByteString IO ()
applyParser path = runIdentityP loop
  where
    loop = do
        bs <- request ()
        let sc = classify  (initPos path) (B8.unpack bs)
        lift $  B8.putStrLn (tokensParserToByteString sc)

tokensParserToByteString :: (Show (IO J2s)) =>  [Token] -> B.ByteString
tokensParserToByteString tokens = B8.pack(show (parseIO pJ2s tokens))


handlerParser :: (CheckP p, Show (IO J2s)) => FilePath -> Session (ExceptionP p) SafeIO ()
handlerParser path = do
    canRead <- tryIO $ fmap readable $ getPermissions path
    isDir   <- tryIO $ doesDirectoryExist path
    isValidExtension <- tryIO $ evaluate ((snd (splitExtension path) == ".java" || snd (splitExtension path) == ".mora") && (snd (splitFileName path) /= "EncodeTest.java") && (snd (splitFileName path) /= "T6302184.java") && (snd (splitFileName path) /= "Unmappable.java"))
    when (not isDir && canRead && isValidExtension) $
        (readFileSP 10240 path >-> try . applyParser) path


readFileSP
:: (CheckP p)
=> Int -> FilePath -> () -> Producer (ExceptionP p) B.ByteString SafeIO ()
readFileSP chunkSize path () =
    bracket id (openFile path ReadMode) hClose $ \handle -> do
        let loop = do
                eof <- tryIO $ hIsEOF handle
                unless eof $ do
                    bs <- tryIO $ B.hGetSome handle chunkSize
                    respond bs
                    loop
        loop
andrea
  • 25
  • 4
  • Can you show a complete error message please? – Code-Apprentice Aug 24 '16 at 00:06
  • [This](http://stackoverflow.com/questions/37119459/no-instance-for-show-io-arising-from-a-use-of-print) might help. – Code-Apprentice Aug 24 '16 at 00:08
  • AFAIK, `main` must have type `main :: IO()` or `main :: [String] -> IO()`. – Code-Apprentice Aug 24 '16 at 00:09
  • the complete error message is: > cabal build Building java2scala-1.0... Preprocessing library java2scala-1.0... In-place registering java2scala-1.0... Preprocessing executable 'java2scala' for java2scala-1.0... Preprocessing executable 'test' for java2scala-1.0... [5 of 5] Compiling Main ( test/Main.hs, dist/build/test/test- tmp/Main.o ) test/Main.hs:27:1: No instance for (Show (IO J2s)) arising from a use of ‘main’ In the expression: main When checking the type of the IO action ‘main’ – andrea Aug 24 '16 at 00:21
  • Please edit your question so you can use proper formatting. – Code-Apprentice Aug 24 '16 at 00:30
  • Yeah, edited Thanks! . Problem is resolved :-) – andrea Aug 24 '16 at 00:41

1 Answers1

2

A signature like Show (IO J2s) => IO () almost never makes sense. What this expresses is basically “provided the universe is crafted such that IO J2s has a Show instance, I give you an IO () action”. Well, if the universe has that property, then give us IO () action right now. Keep nasty chipsconstraints!
Constraints only really make sense if you apply them to type variables, i.e. if you're writing code that's polymorphic over several different, but not all types. (Like with CheckP p). But a constraint applied to concrete types does little more than defer type errors.

IO J2s has no Show instance. And it can't have such an instance: this is an IO action. It could be a complete subprogram that might execute costly computations, call commercial third-party library code, launch some missiles... and only in the very end return a J2s value. How do you expect to pack all the information of something so possibly complex into a simple string?

What possibly does have a Show instance is J2s. If you're in the IO monad anyway and have an IO J2s action, you can at any point fetch the J2s value from it by monad-binding that action (i.e. executing the subprogram) and just showing the J2s value. In your case:

tokensParserToByteString :: [Token] -> IO B.ByteString
tokensParserToByteString tokens = fmap (B8.pack . show) $ parseIO pJ2s tokens

I case you're confused about fmapping in the IO functor, this is equivalent to

tokensParserToByteString :: [Token] -> IO B.ByteString
tokensParserToByteString tokens = do
     j2sValue <- parseIO pJ2s tokens
     return . B8.pack $ show j2sValue

Of course you then need to adapt applyParser because tokensParserToByteString is now an IO action. Easy enough with the =<< operator:

applyParser :: Proxy p => String -> Consumer p B.ByteString IO ()
applyParser path = runIdentityP loop
  where
    loop = do
        bs <- request ()
        let sc = classify  (initPos path) (B8.unpack bs)
        lift $ B8.putStrLn =<< tokensParserToByteString sc
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319