2016-07-30 17 views
6

Immer wenn ich über eine neue Sprache nachdenke - haskell in diesem Fall - versuche ich einen primitiven grep-Klon zu hacken, um zu sehen, wie gut die Sprachimplementierung und/oder ihre Bibliotheken bei der Textverarbeitung sind, weil das ein wichtiger Anwendungsfall ist mich.Primitiver aber effizienter Grep-Klon in Haskell?

Inspiriert von code on the haskell wiki, kam ich mit dem folgenden naiven Versuch auf:

{-# LANGUAGE FlexibleContexts, ExistentialQuantification #-} 

import Text.Regex.PCRE 
import System.Environment 

io :: ([String] -> [String]) -> IO() 
io f = interact (unlines . f . lines) 

regexBool :: forall r l . 
    (RegexMaker Regex CompOption ExecOption r, 
    RegexLike Regex l) => 
    r -> l -> Bool 
regexBool r l = l =~ r :: Bool 

grep :: forall r l . 
    (RegexMaker Regex CompOption ExecOption r, RegexLike Regex l) => 
    r -> [l] -> [l] 
grep r = filter (regexBool r) 

main :: IO() 
main = do 
    argv <- getArgs 
    io $ grep $ argv !! 0 

Dies zu tun, was ich will, es zu sein scheint, aber leider ist es wirklich langsam - etwa 10-mal langsamer als ein Python-Skript, das das Gleiche macht. Ich nehme an, es ist nicht die Regex-Bibliothek, die hier die Schuld trägt, weil es in PCRE anruft, die schnell genug sein sollte (die Umstellung auf Text.Regex.Posix verlangsamt die Dinge ein wenig weiter). Also muss es die String Implementierung sein, die aus theoretischer Sicht lehrreich ist, aber ineffizient nach dem, was ich gelesen habe.

Gibt es eine Alternative zu String s in Haskell, die sowohl effizient und bequem sind (dh es gibt wenig oder keine Reibung, wenn sie mit, dass anstelle von String s schaltend) und die vollständig und korrekt behandelt UTF-8 kodierten Unicode sowie Wie andere Kodierungen ohne zu viel Aufwand wenn möglich? Etwas, das jeder benutzt, wenn er Textverarbeitung in Haskell macht, aber ich weiß es einfach nicht, weil ich ein kompletter Anfänger bin?

+7

Verwenden Sie [Text] (https://hackage.haskell.org/package/text-1.2.2.1/docs/Data-Text.html) – ErikR

+2

Ich wollte nur darauf hinweisen, dass C-ähnliche Geschwindigkeiten möglich ist, aber Es könnte einige Anstrengungen erfordern. Werfen Sie einen Blick auf __cgrep__ - http://awgn.github.io/cgrep/ – ErikR

+4

'String' ist ein low-performance, Lazy-String, der für einfache kurze Strings" fein "ist, aber für ernsthafte Textmanipulation ungeeignet ist. 'Text' ist der Hochleistungstyp für die Unicode-Textbearbeitung. (Es gibt auch 'ByteString', das ist _nicht_ für Text, sondern für Bytefolgen.) – chi

Antwort

1

Es ist möglich, dass die langsame Geschwindigkeit durch Verwendung des Listentyps der Standardbibliothek verursacht wird. Ich habe in der Vergangenheit oft Leistungsprobleme damit bekommen.

Es wäre eine gute Idee, Ihre ausführbare Datei zu profilieren, um zu sehen, wo sie ihre Zeit verbringt: Tools for analyzing performance of a Haskell program. Profiling Haskell-Programme ist wirklich einfach (kompilieren Sie mit einem Schalter und führen Sie Ihr Programm mit einem zusätzlichen Argument, und der Bericht wird in eine Textdatei im aktuellen Arbeitsverzeichnis geschrieben).

Als eine Randnotiz verwende ich genau den gleichen Ansatz wie Sie beim Erlernen einer neuen Sprache: Erstellen Sie etwas, das funktioniert. Meine Erfahrung mit Haskell ist, dass ich leicht eine oder zwei Größenordnungen erreichen kann, indem ich Profilerstellung und relativ einfache Änderungen (normalerweise ein paar Zeilen) mache.

+0

Danke für den Tipp versuchen Ich wusste nicht, dass Haskell so eine schöne Profiling-Unterstützung hat! Ich denke, ich verbringe etwa zwei Drittel der Zeit in 'io' und ein Drittel in' regexBool' (siehe oben), also keine wirklichen Überraschungen - Ich muss diese Anrufe nur noch schneller machen ... Was mit "Text" anstelle von "String" machbar ist, wie von anderen Kommentatoren oben erwähnt, nur Probleme sind, ich konnte mein Programm nicht bekommen Tycheck mit dieser Modifikation bisher. – dlukes

+0

@dlukes - hängt davon ab, welche regex-Bibliothek du verwendest - Ich denke, Regex-Heavy hat 'Text'-Unterstützung, die anderen scheinen nur' String'/'ByteString' zu sein, aber vielleicht ist dies gut genug für deine Bedürfnisse. – epsilonhalbe