Al tratar con tipos de datos algebraicos considerables en Haskell, hay un recorrido recursivo particular no capturado al plegar sobre el tipo de datos. Por ejemplo, supongamos que tengo un tipo simple de datos que representa las fórmulas en la lógica de proposiciones, y un pliegue definido sobre él:Recorrido recursivo de abajo hacia arriba de tipos de datos algebraicos
type FAlgebra α φ =
(φ, φ, -- False, True
α -> φ, -- Atom
φ -> φ, -- Negation
φ -> φ -> φ, -- Conjunction
φ -> φ -> φ, -- Disjunction
φ -> φ -> φ, -- Implication
φ -> φ -> φ) -- Bi-implication
fold :: FAlgebra α φ -> Form α -> φ
fold (f,t,lit,not,con,dis,imp,iff) = fold' where
fold' (Fls) = f
fold' (Tru) = t
fold' (Lit α) = lit α
fold' (Not φ) = not (fold' φ)
fold' (Con φ ψ) = con (fold' φ) (fold' ψ)
fold' (Dis φ ψ) = dis (fold' φ) (fold' ψ)
fold' (Imp φ ψ) = imp (fold' φ) (fold' ψ)
fold' (Iff φ ψ) = iff (fold' φ) (fold' ψ)
Este esquema de recursión proporciona una respuesta sucinta a recursiones como de evaluación o la búsqueda de literales:
eval :: (Ord α) => Map α Bool -> Form α -> Bool
eval v = fold (False, True, (fromJust . flip M.lookup v),
not, (&&), (||), ((||) . not), (==))
literals :: (Ord α) => Form α -> Set α
literals = fold (S.empty, S.empty, S.singleton, id,
S.union, S.union, S.union, S.union)
Sin embargo, no funciona tan bien cuando deseo "barrer" el tipo de datos. En lo siguiente, Simp es una función auxiliar definida por necesario de patrones:
simplify :: Form α -> Form α
simplify (Not φ) = simp (Not (simplify φ))
simplify (Con φ ψ) = simp (Con (simplify φ) (simplify ψ))
simplify (Dis φ ψ) = simp (Dis (simplify φ) (simplify ψ))
simplify (Imp φ ψ) = simp (Imp (simplify φ) (simplify ψ))
simplify (Iff φ ψ) = simp (Imp (simplify φ) (simplify ψ))
simplify φ = φ
Uso de un pliegue para definir simplificar, por supuesto, genera resultados incorrectos. Por ejemplo, lo siguiente no es equivalente:
simplify = fold (Fls, Tru, Lit, (simp . Not), con Con, con Dis, con Imp, con Iff)
where con f φ ψ = simp (f φ ψ)
¿Cuál es la mejor solución para simplificar recursividad como ? ¿Debo definir un cruce genérico similar al doblez sobre el tipo de datos, o hay un patrón de recursión estándar para definir tales funciones?
Por las dudas, agregue el enlace al documento. –
@Yasir: Añadido. Encontré un enlace funcional que no es de paywall. – nominolo
Puede agregar el enlace como comentario, en caso de que cambie de opinión y actualice la pregunta con más datos útiles más adelante (posiblemente agregando el enlace). De esta forma, no obtendrás respuesta en CWed. :-) –