4

I am new to both USB drivers and Haskell. I am trying to connect to Tomu (an ARM micocontroller that fits in a USB port) using System.USB. I tried this example: https://github.com/basvandijk/usb-example/blob/master/example.hs, but it is several years out of date. I am trying to do hello world on USB, but getting type errors.

The following code works:

module Lib where

import System.USB
import System.USB.IO
import Data.Vector 
import Data.Maybe

getOneDesc :: Int -> IO (VendorId, ProductId) 
getOneDesc n = do
    usbConn <- newCtx
    devList <- getDevices usbConn
    f <- getDeviceDesc $ devList ! n
    let f0 = deviceVendorId f
    let f1 = deviceProductId f
    return (f0, f1)

At the repl, I can type getOneDesc 0 and I get something like this:

(300, 42)

I figured I ought to be able to do something like this:

isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> Bool
isThisDeviceTheOneIWant n a b = do
    (x, y) <- getOneDesc n
    return (x == a) && (y == b)

But I encounter type errors.

Can anybody see what's wrong with this?

0

1 Answer 1

5

Your getOneDesc is an IO (VendorId, ProductId), so that means that the result type of your return (x == a) && (y == b) has type IO Bool. So you should change the type of your function. You must also add parentheses around the argument you pass to return (because in Haskell, return is not a keyword, just a plain function).

isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> IO Bool
isThisDeviceTheOneIWant n a b = do
    (x, y) <- getOneDesc n
    return ((x == a) && (y == b))

You can not make the isThisDeviceTheOneIWant return a Bool, since the getOneDesc returns an IO (VendorId, ProductId), and you can not get an a out of an IO a.

We can, like @DanielWagner says, use fmap :: Functor f => (a -> b) -> f a -> f b to process the result of the getOneDesc n, like:

isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> IO Bool
isThisDeviceTheOneIWant n a b = fmap ((a, b) ==) (getOneDesc n)

or use (<$>) :: Functor f => (a -> b) -> f a -> f b which is the same as fmap:

isThisDeviceTheOneIWant :: Int -> VendorId -> ProductId -> IO Bool
isThisDeviceTheOneIWant n a b = ((a, b) ==) <$> getOneDesc n
1
  • And if you want to get fancy, you could write isThisDeviceTheOneIWant n a b = ((a,b)==) <$> getOneDesc n. I recommend this for the expert, so that readers need not double-check for something sneaky going on in this otherwise simple do block; but for a beginner it might be a bit much. Commented May 17, 2019 at 22:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.