Estoy tratando de aprender Haskell y después de un artículo en reddit sobre las cadenas de texto de Markov, decidí implementar la generación de texto de Markov primero en Python y ahora en Haskell. Sin embargo, noté que mi implementación de Python es mucho más rápida que la versión de Haskell, incluso Haskell está compilada con código nativo. Me pregunto qué debo hacer para que el código Haskell funcione más rápido y por ahora creo que es mucho más lento porque utilizo Data.Map en lugar de hashmaps, pero no estoy seguroOptimizar el código Haskell
Voy a publicar el código Python y Haskell también. Con los mismos datos, Python tarda alrededor de 3 segundos y Haskell está más cerca de 16 segundos.
No hace falta decir que voy a tomar cualquier crítica constructiva :).
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."
Interesante, también en busca de la respuesta. 16 versus 3 segundos es realmente una gran diferencia. – wvd
La sangría parece haber sido destrozada por el código de Python, por cierto ... –
No creo que su código Haskell logre lo que usted quiere. Si comprueba el resultado, verá que no hay valores mayores que 2 en los mapas 'M.Map String Int'. ¿Quiere decir 'n + o' o' o + 1' en lugar de 'n + 1'? –