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?

James Strieter
  • 775
  • 3
  • 10

1 Answers1

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
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 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. – Daniel Wagner May 17 '19 at 22:08