8
votes

La façon de Haskell d'accepter l'utilisateur d'entrer un utilisateur saisi de temps?

Je commence juste à apprendre Haskell, et c'est une façon très différente de penser que ce que je suis habitué à (les langues de style C).

Quoi qu'il en soit, pour un problème que je travaille sur j'ai besoin recevoir une entrée utilisateur. Il viendra sous la forme p> xxx pré>

par exemple. Le format est la première ligne indique le nombre de lignes qui suivent. Ma première pensée était que je lisais la première ligne, puis une boucle d'exécution de ce nombre de fois. C'est Haskell cependant! Pour autant que je sache, les boucles ne sont pas possibles. P>

Ma prochaine pensée était que j'utiliserais la première ligne d'entrée pour remplir une liste avec l'autre nombre N nombre de nombres qui suivent. Je ne sais pas comment je ferais cela. Je suis ici parce que je ne suis même pas sûr de ce que je voudrais chercher à le comprendre. P>

Merci d'avance pour me montrer la façon de faire de la part de Haskell. Il est difficile jusqu'à présent, mais j'entends des critiques de rave des gens qui sont "éclairés", donc je pense que cela ne peut pas faire mal d'apprendre la langue moi-même. P>

Voici le code qui va courir une fois tout simplement bien , mais doit être exécuté une fois pour chacun des secondes à N lignes qui suivent la première ligne. P> xxx pré>

(aussi, j'aimerais entendre s'il y a d'autres améliorations que je pouvais faire à mon code, mais dans ce cas particulier, il est pour une concurrence de résoudre un problème dans le moins de caractères possible. Je ne veux pas être plus précis au cas où d'autres personnes essaient de rechercher une réponse à la même chose Problème.) P>

Edit: Merci pour toutes les réponses. J'ai finalement eu quelque chose qui se comportait comment je voulais. Je mets le code pour cela ci-dessous pour la postérité. Malheureusement, même s'il a passé les cas de test avec des couleurs volantes, les données réelles qu'ils ont testées étaient différentes, et tout ce qu'ils me disent, c'est que j'ai eu la "mauvaise réponse". Ce code "fonctionne" mais ne vous obtient pas la bonne réponse. P>

import Control.Monad
l n = (-1)^n/(2*(fromIntegral n)+1)
a m = sum [l n | n <- [0..(m-1)]]
main =
    do  b <- readLn
        s <- replicateM b readLn
        mapM_ print [a c | c <- s]


3 commentaires

Peut-être que c'est une erreur d'arrondi? Peut-être essayez peut-être d'utiliser des nombres rationnels pour tout ce qui convient à un flotteur à la dernière minute: ( import data.ratio , l :: entier -> rationnel et mapm_ (Imprimer. realtofrac) )


C'était une sorte d'erreur d'arrondi. Même après que je l'ai fait, c'était faux. Mon problème était que j'étais trop précis. Je donnais comme 16 chiffres après la décimalité de la précision, mais ils ne voulaient que 15 chiffres. Y a-t-il une façon de faire ça? Ce problème n'est pas quelque chose que vous rencontreriez dans la vie réelle. La plupart des entreprises ne demanderaient jamais moins de précision et autant de caractères que possible (menant à ces terribles noms de variables de caractère)


Vous n'avez pas besoin de construire une liste juste pour avoir une boucle: Main = do {b <- Readln; ReplicateM_ B (DO {C <- LISTLN; impression (a c)})} . Ou des boucles peuvent être codées directement avec Récursion: MAIN = READLN >> = boucle ; boucle n | n <1 = retour () | Sinon = readln >> = (Imprimer. a) >> boucle (N-1) .


4 Réponses :


10
votes

Tout d'abord, vous pouvez faire une boucle juste à Haskell. Cela arrive tout le temps. Vous n'avez tout simplement pas de constructions syntaxiques pour cela, car il n'y a pas besoin pour eux.

La plupart du temps, des boucles générales courantes sont mises en bibliothèques. Dans ce cas, la boucle dont vous avez besoin est dans les bibliothèques standard, dans le module contrôler.monad . C'est ce qu'on appelle réplicateem . Il a la signature de type monad m => int -> m a -> m [a] . Pour spécialiser cette signature pour votre cas, il aurait le type int -> io int -> io [int] . Le premier argument est le nombre de fois à boucle. La seconde est l'action de l'IO à courir sur chaque boucle. Le résultat de la fonction est une action IO qui produit la liste des entrées.

Donc, si vous avez ajouté entrées <- Replicatem B LISTLN à votre bloc de fichiers, il mettrait une liste nommée entrées dans la portée contenant les valeurs du b lignes d'entrée suivant la première. Vous pouvez alors cartographier la fonction de votre solution sur ces lignes.


0 commentaires

1
votes

Vous pouvez créer un readinput n n est le nombre de lignes à lire. L'appel Cela soustrait de manière récursive 1 de n à chaque fois. Je suis également un haskell noob, alors cela pourrait ne pas être la meilleure approche. Cela devrait toujours fonctionner, cependant.


0 commentaires

7
votes

La solution de Carl fonctionnera, mais c'est un peu opaque. Si vous vouliez l'écrire, vous pouvez faire quelque chose comme ceci:

readLines :: Int -> IO [Int]
readLines 0 = return []
readLines n = do
   x <- fmap read getLine
   rest <- readLines (n-1)
   return $ x : rest

readSomeNumberOfLines :: IO [Int]
readSomeNumberOfLines = do
   n <- fmap read getLine
   readLines n


0 commentaires

2
votes

Je ne suis pas sûr de ce que exactement vous voulez faire, mais de lire un entier N, puis les nextes suivantes comme des entiers que vous pouvez faire quelque chose comme: xxx

Le Retour $ Somme XS à la fin du cours n'est pas substantiel - s'il n'était pas là, vous auriez besoin d'une signature de type explicite pour Test .

Si vous ne comprenez aucune de ces fonctions, juste howogle eux.


0 commentaires