Próbuję utworzyć parser wyrażenie wyrażeń w Haskell, który działa świetnie do tej pory, ale obecnie walczę o realizację funkcji wyższego rzędu. Mam problem gotowany w dół do prostego przykładu:Wpisany wyrażeń parser
{-# LANGUAGE TypeFamilies,GADTs,FlexibleContexts,RankNTypes #-}
-- A function has an argument type and a result type
class Fun f where
type FunArg f
type FunRes f
-- Expressions are either constants of function applications
data Expr a where
Const :: a -> Expr a
App :: Fun f => f -> FunArg f -> Expr (FunRes f)
-- A very simple function
data Plus = Plus
-- Which takes two integer expressions and returns an integer expression
instance Fun Plus where
type FunArg Plus = (Expr Int,Expr Int)
type FunRes Plus = Int
-- A more complicated function which lifts a function to lists (like in haskell)
data Map f r = Map f
-- For this we need the concept of lifting function arguments:
class Liftable a where
type LiftRes a
-- A singleton argument is lifted by changing the expression type from a to [a]
instance Liftable (Expr a) where
type LiftRes (Expr a) = Expr [a]
-- Two function arguments are lifted by lifting each argument
instance (Liftable a,Liftable b) => Liftable (a,b) where
type LiftRes (a,b) = (LiftRes a,LiftRes b)
-- Now we can declare a function instance for Map
instance (Fun f,Liftable (FunArg f),r ~ LiftRes (FunArg f)) => Fun (Map f r) where
type FunArg (Map f r) = r
type FunRes (Map f r) = [FunRes f]
-- Now a parser for functions:
parseFun :: [String] -> (forall f. Fun f => f -> a) -> a
-- The parser for the plus function is easy:
parseFun ["plus"] f = f Plus
-- But the parser for map is not possible:
parseFun ("map":sym) f
= parseFun sym (\fun -> f (Map fun))
Problem wydaje się, że nie ma sposobu, aby przekonać się, że każdy typ sprawdzania LiftRes sam jest podnoszona, bo deklaracje rekurencyjne klasy są zabronione.
Moje pytanie brzmi: jak to zrobić? Czy istnieją inne przykłady parserów wyrażeń tekstowych, z których mogłem korzystać z podpowiedzi?
EDIT: Wydaje się, że this discussion about type family constraints wydaje się być bardzo podobne. Jednak nie udało mi się sprawić, aby ich rozwiązanie działało w moim przypadku, może ktoś może pomóc w tym?
Problem z dodaniem 'Liftable' ograniczenie do klasy funkcji jest to, że wymaga ode mnie, aby dodać' podnoszona r' na przykład mapy, które następnie wymaga instancję 'podnoszona (LiftRes (FunArg f))' w parserze. Proces ten można kontynuować w nieskończoność. Wyjaśnienie uwagi: Poprawisz, w prawdziwym kodzie parsuję wyrażenia lisp, ale nie chciałem zawracać czytelnikom konieczności instalowania dodatkowych pakietów. – henning
Dzięki, to jest to, o co chodzi także w drugim poście (chyba). Nie mogę jednak sprawić, aby twój kod zadziałał, ale wyświetla ten sam komunikat o błędzie, co poprzednio. Czy muszę zmienić coś innego? Czy brakuje mi niektórych flag kompilatora itp.? – henning
Mogę tylko spekulować, w jaki sposób używasz tego wszystkiego. Jeśli rzeczywisty błąd, który otrzymujesz, nie jest powtarzalny na twoim przykładzie, trudno mi zasugerować coś, co faktycznie działa w twoim scenariuszu. – kosmikus