Piesek64
Piesek64

Reputation: 67

Couldn't match type `[Char]' with `Value'

I am writing package manager and I stuck at checking is file installed.

[1 of 1] Compiling Main             ( ../src/beaver.hs, ../src/.o/Main.o)
../src/beaver.hs:57:37:
Couldn't match type `[Char]' with `Value'
Expected type: [Value]
  Actual type: [[Char]]
In the second argument of `mapM', namely `(splitOn " " files)'
In a stmt of a 'do' block: mapM isFileInstalled (splitOn " " files)

Here is code of problematic function(s):

installpkg = do
          args <- getArgs
          pkgname <- readProcess "beaver-pkgname" [(args !! 1)] ""
          extractpkg pkgname
          files <- metaprop "files" pkgname
          mapM isFileInstalled (splitOn " " files)
 isFileInstalled f = do
            dbcon <- openConnection "/var/lib/beaver/pkgs.db"
            res <- execParamStatement dbcon "SELECT owner FROM files WHERE path = :path" [(":path", f)] :: IO (Either String [[Row Value]])
            when (null res) (putStrLn "file exists")
            closeConnection dbcon

I were searching for solution but I cannot find anything.

Also, is there a way to convert string or text to FilePath?

Upvotes: 1

Views: 287

Answers (1)

Shoe
Shoe

Reputation: 76300

The type of execParamStatement in isFileInstalled is:

execParamStatement :: SQLiteResult a => SQLiteHandle -> String -> [(String, Value)] -> IO (Either String [[Row a]])

that means that [(":path", f)] is of type [(String, Value)] and f is dedecued to be of type Value.

This all means that isFileInstalled is deduced to take a Value as first argument.

Now in the other installpkg function you are calling:

mapM isFileInstalled (splitOn " " files)

and mapM is deduced to be from:

mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)

to:

mapM :: (Value -> IO b) -> [Value] -> IO [b]

for whatever b is deduced there (it's hard to figure out because you don't put explicit type signatures for functions).

This all means that mapM is expected to get a list of [Value] from (splitOn " " files), which it's not. (splitOn " " files) is returning a [String] which is incompatible with [Value].

Since Value has a constructor that takes a String, you can use:

(map Text . splitOn " " $ files)

instead of:

(splitOn " " files)

and make it type check at least.


Also, is there a way to convert string or text to FilePath?

As far as FilePath is concerned, that's just an alias for String, so you don't need to convert to it to use it in the context where it's required a String.


Finally for the sake of those reading the code and you reasoning about it, write top level types signatures for functions, thanks.

Upvotes: 3

Related Questions