2 votes

Utiliser le port série de manière interactive avec Haskell

J'essaie d'envoyer un message via le port série à un Lego NXT en utilisant le mode interactif de Haskell, mais je n'arrive pas à trouver comment utiliser la fonction serialport fonctionne correctement.

J'ai un message qui doit jouer une tonalité sur le NXT qui est de type ByteString

> let message = pack ([6, 0 ,0, 3, 224, 1, 208, 7]::[Word8])

Je peux ouvrir le port série en utilisant openSerial .

openSerial :: FilePath -> SerialPortSettings -> IO SerialPort
> let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings

Mais ensuite, je suis coincé. Comment dois-je utiliser le send fonction ?

send :: SerialPort -> B.ByteString -> IO Int
> send mybrick message

Cela me donne le message d'erreur suivant.

<interactive>:31:6:
    Couldn't match expected type `SerialPort'
                with actual type `IO SerialPort'
    In the first argument of `send', namely `mybrick'
    In the expression: send mybrick message
    In an equation for `it': it = send mybrick message

7voto

J. Abrahamson Points 27606

Vous devez séquence votre Monad les calculs. Je l'écrirai de manière générale et simple puis spécifiquement pour votre situation.


Le problème que vous avez est que vous avez une fonction f :: A -> IO B et une autre fonction g :: B -> IO C qui semblent devoir être combinables, mais ne le sont pas vraiment - la deuxième fonction nécessite une fonction simple B et non le IO B que le premier renvoie.

C'est exactement là que le pouvoir de Monad entre en jeu. Sachant que IO est une monade, nous pouvons utiliser une fonction comme (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c pour combiner ces Monad les fonctions de l'entreprise. En fait, déjà, f >=> g :: A -> IO C comme nous l'exigeons.

Nous pouvons également utiliser do ce qui nous obligerait à "lier" le type de retour de l'option f et l'appliquer ensuite à g pour obtenir la sortie.

\a -> do b <- f a
         g b

ce qui nous donne une fonction de type A -> IO C encore. En fait, cette do est essentiellement la définition de (>=>) .


Comment cela s'applique-t-il dans votre cas particulier ? Eh bien,

let mybrick = openSerial "/dev/tty.NXT-DevB" defaultSerialSettings

vous donne un mybrick :: IO SerialPort valeur. Afin d'utiliser send :: SerialPort -> ByteString -> IO Int nous devons "déballer" mybrick de la IO Monad . Nous pouvons donc utiliser do notation

do sp <- mybrick
   send sp message

Ou, pour que tout soit plus clair, nous pouvons simplement exécuter le calcul entier en utilisant do notation

do mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
   send mybrick message

2voto

bzn Points 2322

openSerial path settings est une action IO, qui produit un port série. Pour avoir accès au port série, vous devez exécuter cette action à l'intérieur de la monade IO. Votre main pourrait ressembler à quelque chose comme ça :

main = do 
    mybrick <- openSerial "/dev/tty.NXT-DevB" defaultSerialSettings
    let message = pack ([0, 3, 224, 1, 208, 7] :: [Word8])
    send mybrick message

La différence est, que le let La liaison crée juste un nouveau nom pour ce qui vient après le signe égal. Dans ce cas, cela conduit à mybrick avoir un type IO SerialPort comme le dit le message d'erreur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X