2011-09-21 13 views
7

W moim bardzo prostego programu zabawka logiczna wypowiedzi, mam następującą funkcję ocena:uniknąć wyraźnego przejścia tabeli przeglądowej

eval' :: Expr -> M.Map Char Bool -> Bool 

eval' (Const c) values = c 

eval' (Var v) values = M.findWithDefault False v values 

eval' (Not x) values = not (eval' x values) 

eval' (And a b) values = eval' a values && eval' b values 

eval' (Or a b) values = eval' a values || eval' b values 

eval' (Xor a b) values = eval' a values /= eval' b values 

Zastanawiałem się, czy istnieje sposób, aby przekazać tablicę values niejawnie? Może z pomocą Monad?

Odpowiedz

4

W tym przypadku, nie przechodzą values w ogóle:

eval' :: Expr -> M.Map Char Bool -> Bool 
eval' e values = eval'' e 

    where 
    eval'' (Const c) = c 
    eval'' (Var v) = M.findWithDefault False v values 
    eval'' (Not x) = not (eval'' x) 
    ... 
+0

Nie tylko jest to prostsze, ale prawdopodobnie również bardziej wydajne. Uważam, że nazywa się to statyczną transformacją argumentów. –

13

Monady będzie działać, ale moim zdaniem przy użyciu Applicative jest czystsze tutaj:

eval' :: Expr -> M.Map Char Bool -> Bool 
eval' (Const c) = pure c 
eval' (Var v) = M.findWithDefault False v 
eval' (Not x) = not <$> eval' x 
eval' (And a b) = (&&) <$> eval' a <*> eval' b 
eval' (Or a b) = (||) <$> eval' a <*> eval' b 
eval' (Xor a b) = (/=) <$> eval' a <*> eval' b 

ta wykorzystuje instancję ((->) r), jak Reader monada/aplikacyjnych, ale bez owijki newtype.

+0

bym sięgnął po 'Reader' monady, jak acfoltzer zrobił, ale podoba mi się czysty wygląd tego rozwiązania. – pat

+0

'Niejednoznaczne wystąpienie 'Const': Może odnosić się do" Main.Const "lub" Control.Applicative.Const'' No cóż, chciałem zmienić nazwę mojego 'Const' na' Val', tak czy tak :) – fredoverflow

+1

Albo mógłbym just 'import Control.Applicative (pure, (<*>), (<$>))' :) – fredoverflow

9

To jest dokładnie to, co jest dla Reader monad:

monady Reader (zwany także środowisko monada). Reprezentuje obliczenia , które mogą odczytywać wartości ze środowiska współużytkowanego, przekazywać wartości od funkcji do funkcji i wykonywać sub-obliczenia w zmodyfikowanym środowisku .

Jak zauważa sjoerd, monada daje więcej energii, niż trzeba, ale można nadal używać Monada Reader dla tego problemu bez tyle wpisując do:

import qualified Data.Map as M 

import Control.Applicative ((<$>), (<*>)) 
import Control.Monad.Reader 

data Expr = Const Bool 
      | Var Char 
      | Not Expr 
      | And Expr Expr 
      | Or Expr Expr 
      | Xor Expr Expr 

Wystarczy umieścić swój typ środowiska jako pierwszy argument konstruktora typu Reader, a pierwotny typ wyniku jako drugi.

eval' :: Expr -> Reader (M.Map Char Bool) Bool 

Zamiast c jako wartość przypadku Const użyć return podnieść go do monady:

eval' (Const c) = return c 

Kiedy trzeba środowisko dla patrząc wartość zmiennej użytkowania ask. Korzystanie do notacji, można napisać sprawę Var tak:

eval' (Var v) = do values <- ask 
        return (M.findWithDefault False v values) 

myślę, że ładniejsze, choć w użyciu fmap aka <$>:

eval' (Var v) = M.findWithDefault False v <$> ask 

Podobnie, jednoskładnikowa not można fmap ped ponad Wynik rekursji:

eval' (Not x) = not <$> eval' x 

Fina lly, wystąpienie Reader Applicative sprawia przypadki binarne przyjemne:

eval' (And a b) = (&&) <$> eval' a <*> eval' b 

eval' (Or a b) = (||) <$> eval' a <*> eval' b 

eval' (Xor a b) = (/=) <$> eval' a <*> eval' b 

Następnie, aby dostać to wszystko się zaczęło, oto pomocnik stworzyć wstępną środowiska i uruchomić obliczenia:

eval :: Expr -> [(Char,Bool)] -> Bool 
eval exp env = runReader (eval' exp) (M.fromList env) 
2

Lubisz znasz rozszerzenie implicit parameters? To może być pomocne.

+2

Ostatnio była [dyskusja na temat r/haskell] (http://www.reddit.com/r/haskell/comments/kbzjk/what_about_the_implicitparams_haskell_language/). Wydaje się, że konsensus jest taki, że nie jest to użyteczne, głównie dlatego, że przeciekają one do podpisów typu, zmuszając w ten sposób do nieużywania sygnatur typu lub kończąc na tej samej liczbie elementów, które próbowaliście pozbyć. – hammar

+0

@hammar Dobra uwaga. – fuz

Powiązane problemy