2015-07-14 14 views
5

Useresti se/else scrivere questo algoritmo in Haskell? C'è un modo per esprimerlo senza di loro? È difficile estrarre le funzioni fuori dal centro che hanno un significato. Questo è solo l'output di un sistema di apprendimento automatico.Come lo esprimeresti in Haskell?

Sto implementando l'algoritmo per la classificazione di segmenti di contenuto html come Contenuto o Boilerplate descritto here. Questo ha i pesi già codificati.

curr_linkDensity <= 0.333333 
| prev_linkDensity <= 0.555556 
| | curr_numWords <= 16 
| | | next_numWords <= 15 
| | | | prev_numWords <= 4: BOILERPLATE 
| | | | prev_numWords > 4: CONTENT 
| | | next_numWords > 15: CONTENT 
| | curr_numWords > 16: CONTENT 
| prev_linkDensity > 0.555556 
| | curr_numWords <= 40 
| | | next_numWords <= 17: BOILERPLATE 
| | | next_numWords > 17: CONTENT 
| | curr_numWords > 40: CONTENT 
curr_linkDensity > 0.333333: BOILERPLATE 

risposta

6

Dal momento che ci sono solo tre i percorsi in questo albero decisionale che conduce ad uno stato BOILERPLATE, avevo appena iterare e semplificare:

isBoilerplate = 
    prev_linkDensity <= 0.555556 && curr_numWords <= 16 && prev_numWords <= 4 
    || prev_linkDensity > 0.555556 && curr_numWords <= 40 && next_numWords <= 17 
    || curr_linkDensity > 0.333333 
+4

Penso che si desidera 'o', non' any'. Potresti anche usare '||', oppure usare 'and' invece di' && 's. –

11

Non semplificando la logica manualmente (supponendo che si potrebbe generare questo codice automaticamente), penso che usando MultiWayIf sia abbastanza pulito e diretto.

{-# LANGUAGE MultiWayIf #-} 

data Stats = Stats { 
    curr_linkDensity :: Double, 
    prev_linkDensity :: Double, 
    ... 
} 

data Classification = Content | Boilerplate 

classify :: Stats -> Classification 
classify s = if 
    | curr_linkDensity s <= 0.333333 -> if 
     | prev_linkDensity s <= 0.555556 -> if 
     | curr_numWords s <= 16 -> if 
      | next_numWords s <= 15 -> if 
      | prev_numWords s <= 4 -> Boilerplate 
      | prev_numWords s > 4 -> Content 
      | next_numWords s > 16 -> Content 
     ... 

e così via.

Tuttavia, poiché questo è così strutturato, solo un albero di if/else con confronti, si consideri anche la creazione di una struttura di dati dell'albero decisionale e la scrittura di un interprete per esso. Questo ti permetterà di fare trasformazioni, manipolazioni, ispezioni. Forse ti comprerà qualcosa; la definizione di linguaggi in miniatura per le vostre specifiche può essere sorprendentemente utile.

data DecisionTree i o 
    = Comparison (i -> Double) Double (DecisionTree i o) (DecisionTree i o) 
    | Leaf o 

runDecisionTree :: DecisionTree i o -> i -> o 
runDecisionTree (Comparison f v ifLess ifGreater) i 
    | f i <= v = runDecisionTree ifLess i 
    | otherwise = runDecisionTree ifGreater i 
runDecisionTree (Leaf o) = o 

-- DecisionTree is an encoding of a function, and you can write 
-- Functor, Applicative, and Monad instances! 

Poi

classifier :: DecisionTree Stats Classification 
classifier = 
    Comparison curr_linkDensity 0.333333 
     (Comparison prev_linkDensity 0.555556 
     (Comparison curr_numWords 16 
      (Comparison next_numWords 15 
      (Comparison prev_numWords 4 
       (Leaf Boilerplate) 
       (Leaf Content)) 
      (Leaf Content) 
      ... 
+2

Per il primo metodo, l'estensione 'MultiWayIf' consente di scrivere quella più carina, sostituendo' case() di _' con 'if'. –

+0

@ ØrjanJohansen, che è bello, aggiornato. :-) – luqui

+3

Commento secondario: ho un disgusto personale per le guardie che hanno lo scopo di coprire tutti i casi (vale a dire essere esaurienti) e non usare "altrimenti" per l'ultima guardia. Io uso 'altrimenti' perché trovo che esprima meglio l'intento, non devo ripetere la condizione due volte ed è più efficiente di qualsiasi altra cosa. Inoltre, quando un 'if 'interno ha rami non esaustivi, è molto facile (almeno per me) pensare che Haskell tornerà indietro al prossimo ramo' if' esterno. Tuttavia, questo non è il caso e si verifica un errore di runtime match non esaustivo. Per questi motivi preferisco decisamente l'ultima alternativa – chi