【问题标题】:No instance for (Show (FilePath -> IO [FilePath])) arising from a use of ‘print’(Show (FilePath -> IO [FilePath])) 没有因使用“print”而产生的实例
【发布时间】:2018-05-22 22:17:43
【问题描述】:

我正在尝试修复并运行 Real World Haskell 书中的每个示例,并在此过程中学习一些东西,但我被困在了 chapter 9。通过阅读 cmets,我得到了以下代码进行编译:

FoldDir.hs:

import ControlledVisit
import Data.Char (toLower)
import Data.Time.Clock (UTCTime(..))
import System.Directory (Permissions(..))
import System.FilePath ((</>), takeExtension, takeFileName)

data Iterate seed
  = Done { unwrap :: seed }
  | Skip { unwrap :: seed }
  | Continue { unwrap :: seed }
    deriving (Show)

type Iterator seed = seed -> Info -> Iterate seed

foldTree :: Iterator a -> a -> FilePath -> IO a
foldTree iter initSeed path = do
  endSeed <- fold initSeed path
  return (unwrap endSeed)
  where
    fold seed subpath = getUsefulContents subpath >>= walk seed
    walk seed (name : names) = do
      let path' = path </> name
      info <- getInfo path'
      case iter seed info of
        done @ (Done _) -> return done
        Skip seed'      -> walk seed' names
        Continue seed'
          | isDirectory info -> do
            next <- fold seed' path'
            case next of
              done @ (Done _) -> return done
              seed''           -> walk (unwrap seed'') names
          | otherwise         -> walk seed' names
    walk seed _ = return (Continue seed)

atMostThreePictures :: Iterator [FilePath]
atMostThreePictures paths info
  | length paths == 3
    = Done paths
  | isDirectory info && takeFileName path == ".svn"
    = Skip paths
  | extension `elem` [".jpg", ".png"]
    = Continue (path : paths)
  | otherwise
    = Continue paths
  where
    extension = map toLower (takeExtension path)
    path = infoPath info

countDirectories count info =
  Continue (if isDirectory info then count + 1 else count)

ControlledVisit.hs:

module ControlledVisit where

import Control.Monad (forM, liftM)
import Data.Time.Clock (UTCTime(..))
import System.FilePath ((</>))
import System.Directory
  ( Permissions(..)
  , getModificationTime
  , getPermissions
  , getDirectoryContents
  )
import Control.Exception
  ( bracket
  , handle
  , SomeException(..)
  )
import System.IO
  ( IOMode(..)
  , hClose
  , hFileSize
  , openFile
  )

data Info = Info
  { infoPath :: FilePath
  , infoPerms :: Maybe Permissions
  , infoSize :: Maybe Integer
  , infoModTime :: Maybe UTCTime
  } deriving (Eq, Ord, Show)

getInfo :: FilePath -> IO Info
getInfo path = do
  perms <- maybeIO (getPermissions path)
  size <- maybeIO (bracket (openFile path ReadMode) hClose hFileSize)
  modified <- maybeIO (getModificationTime path)
  return (Info path perms size modified)

traverseDirs :: ([Info] -> [Info]) -> FilePath -> IO [Info]
traverseDirs order path = do
  names <- getUsefulContents path
  contents <- mapM getInfo (path : map (path </>) names)
  liftM concat $ forM (order contents) $ \ info -> do
    if isDirectory info && infoPath info /= path
      then traverseDirs order (infoPath info)
      else return [info]

getUsefulContents :: FilePath -> IO [String]
getUsefulContents path = do
  names <- getDirectoryContents path
  return (filter (`notElem` [".", ".."]) names)

isDirectory :: Info -> Bool
isDirectory = maybe False searchable . infoPerms

maybeIO :: IO a -> IO (Maybe a)
maybeIO act = handle (\ (SomeException _) -> return Nothing) (Just `liftM` act)

traverseVerbose order path = do
  names <- getDirectoryContents path
  let usefulNames = filter (`notElem` [".", ".."]) names
  contents <- mapM getEntryName ("" : usefulNames)
  recursiveContents <- mapM recurse (order contents)
  return (concat recursiveContents)
  where
    getEntryName name = getInfo (path </> name)
    isDirectory info = case infoPerms info of
      Nothing -> False
      Just perms -> searchable perms
    recurse info = do
      if isDirectory info && infoPath info /= path
        then traverseVerbose order (infoPath info)
        else return [info]

但是当我尝试在 GHCi as explained in the book 中运行它时,它会出现一个奇怪的错误,据我所知是关于 GHCi 本身:

Prelude> :l FoldDir.hs
[1 of 2] Compiling ControlledVisit  ( ControlledVisit.hs, interpreted )
[2 of 2] Compiling Main             ( FoldDir.hs, interpreted )
Ok, two modules loaded.
*Main> foldTree atMostThreePictures []

<interactive>:2:1: error:
    • No instance for (Show (FilePath -> IO [FilePath]))
        arising from a use of ‘print’
        (maybe you haven't applied a function to enough arguments?)
    • In a stmt of an interactive GHCi command: print it

我想我理解No instance for (Show (FilePath -&gt; IO [FilePath])) 部分,但我对print it 一无所知。我知道it 是 GHCi 中的一个特殊变量,它存储最后一个表达式的评估结果,我猜代码正在尝试打印一个函数或一个 monad,但我不知道它发生在哪里。

【问题讨论】:

  • foldTree 函数需要 3 个参数,但您只传递了 2 个(如错误消息中所建议的那样)。
  • 在您的调用中添加 path 参数。

标签: haskell ghci


【解决方案1】:

尽可能简单 - 你的函数 foldTree 的签名是:

foldTree :: Iterator a -> a -> FilePath -> IO a

您为其提供了两个参数,一个是Iterator [FilePath] 类型,第二个是FilePath 类型。由于默认的部分应用,这样的调用返回带有签名的函数:

FilePath -> IO [FilePath]

GHCI 想要显示你调用的结果,但它不能,因为这个类型没有定义类型类Show 的实例。因此,它会给您一个错误,准确地说明这一点。

【讨论】:

    猜你喜欢
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多