J'essaie d'apprendre Haskell et après un article dans reddit sur les chaînes de texte Markov, j'ai décidé d'implémenter la génération de texte Markov d'abord en Python et maintenant dans Haskell. Cependant, j'ai remarqué que mon implémentation de Python est bien plus rapide que la version de Haskell, même Haskell est compilé en code natif. Je me demande ce que je devrais faire pour accélérer le code Haskell et pour l'instant je crois que c'est beaucoup plus lent à cause de l'utilisation de Data.Map au lieu de hashmaps, mais je ne suis pas sûr. et Haskell aussi. Avec les mêmes données, Python prend environ 3 secondes et Haskell est plus proche de 16 secondes.Optimisation du code Haskell
Il va sans dire que je vais prendre toute critique constructive :).
import random
import re
import cPickle
class Markov:
def __init__(self, filenames):
self.filenames = filenames
self.cache = self.train(self.readfiles())
picklefd = open("dump", "w")
cPickle.dump(self.cache, picklefd)
picklefd.close()
def train(self, text):
splitted = re.findall(r"(\w+|[.!?',])", text)
print "Total of %d splitted words" % (len(splitted))
cache = {}
for i in xrange(len(splitted)-2):
pair = (splitted[i], splitted[i+1])
followup = splitted[i+2]
if pair in cache:
if followup not in cache[pair]:
cache[pair][followup] = 1
else:
cache[pair][followup] += 1
else:
cache[pair] = {followup: 1}
return cache
def readfiles(self):
data = ""
for filename in self.filenames:
fd = open(filename)
data += fd.read()
fd.close()
return data
def concat(self, words):
sentence = ""
for word in words:
if word in "'\",?!:;.":
sentence = sentence[0:-1] + word + " "
else:
sentence += word + " "
return sentence
def pickword(self, words):
temp = [(k, words[k]) for k in words]
results = []
for (word, n) in temp:
results.append(word)
if n > 1:
for i in xrange(n-1):
results.append(word)
return random.choice(results)
def gentext(self, words):
allwords = [k for k in self.cache]
(first, second) = random.choice(filter(lambda (a,b): a.istitle(), [k for k in self.cache]))
sentence = [first, second]
while len(sentence) < words or sentence[-1] is not ".":
current = (sentence[-2], sentence[-1])
if current in self.cache:
followup = self.pickword(self.cache[current])
sentence.append(followup)
else:
print "Wasn't able to. Breaking"
break
print self.concat(sentence)
Markov(["76.txt"])
-
module Markov
(train
, fox
) where
import Debug.Trace
import qualified Data.Map as M
import qualified System.Random as R
import qualified Data.ByteString.Char8 as B
type Database = M.Map (B.ByteString, B.ByteString) (M.Map B.ByteString Int)
train :: [B.ByteString] -> Database
train (x:y:[]) = M.empty
train (x:y:z:xs) =
let l = train (y:z:xs)
in M.insertWith' (\new old -> M.insertWith' (+) z 1 old) (x, y) (M.singleton z 1) `seq` l
main = do
contents <- B.readFile "76.txt"
print $ train $ B.words contents
fox="The quick brown fox jumps over the brown fox who is slow jumps over the brown fox who is dead."
Intéressant, cherchant aussi la réponse. 16 contre 3 secondes est vraiment une grande différence. – wvd
L'indentation semble avoir été altérée pour le code Python, en passant ... –
Je ne pense pas que votre code Haskell accomplit ce que vous voulez. Si vous vérifiez la sortie, vous verrez qu'il n'y a pas de valeurs supérieures à 2 dans les cartes 'M.Map String Int'. Voulez-vous dire «n + o» ou «o + 1» au lieu de «n + 1»? –