43 votes

Comment écrire une fonction Haskell qui prend une fonction variadique comme argument ?

J'essaie de créer une fonction qui récupère une fonction variadique en tant que un argument c'est-à-dire

func :: (a -> ... -> a) -> a

comment puis-je y parvenir ?

J'ai lu des articles sur fonctions polyvariables et je suis sûr que Oleg l'a déjà fait Cependant, je suis perdu en essayant d'appliquer le modèle à une fonction avec une fonction variadique comme argument. En particulier, l'approche d'Oleg semble fonctionner uniquement avec les extensions de Glasgow et je veux que la solution fonctionne dans Haskell 98 pur (comme Text.Printf fait).

La raison La question que je pose est la suivante : j'essaie de construire une fonction qui prend une fonction booléenne comme argument et vérifie s'il s'agit d'une tautologie, à savoir

isTautology :: (Bool -> ... -> Bool) -> Bool

pour que l'on puisse taper :

isTautology (\x -> x && not x)
isTautology (\x y -> x && y || not y)

Mon problème est que je continue à lire que l'astuce consiste à faire du type de retour un type variable (de sorte qu'il puisse être le résultat ou une autre fonction), mais mon type de retour est fixe (Bool).

56voto

hammar Points 89293

L'astuce est de faire une classe de type pour laquelle vous allez définir une instance pour les fonctions, et une instance pour le type de retour. Le fait qu'il s'agisse d'une Bool n'est pas du tout un problème.

Nous essayons d'écrire une fonction qui prend un argument variadique et qui renvoie une fonction Bool Nous allons donc définir une classe de type avec une telle fonction.

class Stmt a where
    tautology :: a -> Bool

Ensuite, nous définissons une instance pour le type de retour de la fonction variadique. Dans ce cas, il s'agit de Bool .

-- A Bool is a tautology if it's True.
instance Stmt Bool where
    tautology = id

La partie clé est l'instance suivante pour les fonctions qui prennent un Bool et dont le type de retour est un type de notre classe. De cette façon, cette instance sera appliquée plusieurs fois si une fonction prend plusieurs arguments.

-- A function is a tautology if it always returns a tautology.
instance Stmt b => Stmt (Bool -> b) where
    tautology f = tautology (f True) && tautology (f False)

L'écrire de cette façon nécessite FlexibleInstances en raison de la Bool dans la tête de la deuxième instance. Pour faire la même chose avec Haskell 98 pur, nous devrons utiliser une variable de type avec des contraintes appropriées. Nous pouvons par exemple utiliser Bounded et Enum (il existe des instances pour les deux pour Bool ), ou vous pouvez créer votre propre classe qui vous permettra de construire les entrées appropriées.

instance (Enum a, Bounded a, Stmt b) => Stmt (a -> b) where
    tautology f = all (tautology . f) [minBound .. maxBound]

Et nous avons terminé. Essayons-le :

> tautology $ \x y -> (not x && not y) == not (x && y)
False
> tautology $ \x y -> (not x && not y) == not (x || y)
True

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X