54 votes

Comment puis-je me connecter à Haskell?

Je suis d'essayer d'utiliser HSlogger pour obtenir quelques informations sur mon programme. J'ai donc ajouter la ligne suivante à ma fonction

import Data.Word
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Bits
import Data.Int
import Data.ByteString.Parser

import System.Log.Logger
import System.Log.Handler.Syslog


importFile :: FilePath -> IO (Either String (PESFile ))
importFile n = do
     warningM "MyApp.Component2" "Something Bad is about to happen."
     ...

Et qui fonctionne très bien, parce que la fonction est à l'intérieur de IO. Cependant quand j'ai ajouter une ligne similaire à la fonction suivante:

...
parsePES :: Parser PESFile
parsePES = do
        header <- string "#PES"
        warningM "parsing header"
        ...
        return (PESFile ...)

J'obtiens une erreur de type:

 Couldn't match expected type `Parser a0'
                with actual type `String -> IO ()'
    In the return type of a call of `warningM'
    In a stmt of a 'do' expression: warningM "parsing header"
    In the expression:
      do { header <- string "#PES";
           warningM "parsing header";
        ...

Et je comprends tout à fait pourquoi - parsePES est dans l'Analyseur monade, pas le IO monade. Ce que je ne comprends pas ce qu'il faut faire à ce sujet. Ai-je besoin d'une monade transformateur afin que je puisse pile de l'Analyseur monade et de la IO monade ensemble? Comment dois-je faire à ce sujet?

50voto

C. A. McCann Points 56834

Tout d'abord, un rapide avertissement: "enregistrement" n'a pas l'habitude de faire du sentiment en général du code Haskell, car il suppose une certaine sorte de l'exécution séquentielle qui peuvent ou peuvent ne pas être significatifs. Assurez-vous que vous faites une distinction entre la journalisation de la façon dont le programme s'exécute et la journalisation à ce que les valeurs sont calculées. Dans le strict impératif langues, ces sont essentiellement les mêmes, mais en Haskell ils ne le sont pas.

Cela dit, il semble que vous souhaitez ouvrir une session basée sur les valeurs étant calculées, dans le contexte d'une déjà séquentielle et stateful de calcul, qui réussit plutôt bien le même que l'exploitation forestière dans la plupart des autres langues. Cependant, vous avez besoin de la monade à l'appui de certains moyens de le faire. Il ressemble à l'analyseur que vous utilisez est de la HCodecs paquet, ce qui semble être relativement limitée, n'autorise pas l' IO, et n'est pas défini comme une monade transformateur.

Honnêtement, mon conseil serait d'envisager d'utiliser une autre analyse de la bibliothèque. Parsec a tendance à être le choix par défaut, et je pense que attoparsec est populaire à des fins spécifiques (qui pourrait comprendre ce que vous faites). L'un et l'autre vous permettent d'ajouter de journalisation beaucoup plus facilement: Parsec est une monade transformateur, donc vous pouvez le mettre sur le dessus de l' IO , puis utiliser liftIO , alors qu'attoparsec est conçu autour de différentiels de traitement, de sorte que vous pouvez découper votre entrée de journal et les aspects du traitement (même si la journalisation dans l'analyseur peut être plus difficile). Il y a d'autres choix que de bien, mais je ne sais pas assez de détails pour en faire une recommandation. La plupart du combinateur parseur basé sur les bibliothèques ont tendance à avoir assez de conception similaire, donc je m'attends à de portage de votre code serait simple.

Une dernière option, si vous vraiment voulez tenir à ce que vous avez, serait d'examiner la mise en œuvre de l'analyse de la bibliothèque que vous utilisez actuellement et rouler vos propres IO-orienté version de celui-ci. Mais ce n'est probablement pas l'idéal.


Aussi, comme un additif, si vous ce que vous êtes vraiment après n'est en fait pas de journalisation, mais se contenter de les suivre l'exécution de votre programme dans le cadre de développement, vous pouvez trouver le débogueur intégré dans GHCi être plus utile, ou de la bonne vieille printf débogage via le Debug.Trace module.


Edit: Ok, on dirait que vous avez des raisons plausibles pour envisager de déployer votre propre variation. Ce que vous avez environ voulons ici, c'est un ParserT monade transformateur. Voici la définition actuelle de l' Parser:

newtype Parser a = Parser { unParser :: S -> Either String (a, S) }

Le type S est l'analyseur de l'état. Notez que c'est à peu près codé en dur version de StateT S (Either String) a:

newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }

...où est - Either String est considéré comme une erreur de la monade. L' ErrorT monade transformateur fait la même chose:

newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }

Ainsi, lorsque le type de courant est équivalent à StateT S (ErrorT String Identity), ce que vous voulez serait StateT S (ErrorT String IO).

Elle ressemble à la plupart des fonctions du module ne sont pas déconner avec le fonctionnement interne de l' Parser de l'errance, de sorte que vous devriez être en mesure de simplement remplacer les définitions de type, offre le type des instances de classe, écrire votre propre runParser de la fonction, et être bon d'aller.

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