Esiste un modo conveniente per utilizzare un modello come funzione predicata?


10

Di recente mi sono imbattuto in situazioni in cui ho bisogno di passare una funzione predicata in un'altra funzione, e molto spesso la logica che sto cercando è essenzialmente "questo valore corrisponde a questo modello?"

La corrispondenza dei modelli sembra essere preferita nelle dichiarazioni, nei doblocchi e nelle comprensioni di elenchi, ma ci sono un certo numero di funzioni che accettano un predicato a -> Bool, dove sarebbe molto utile passare in qualche modo in un modello. Ad esempio, takeWhile, until, find, span, etc.

Finora ho fatto \a -> case a of MyCons _ -> True; otherwise -> False, o ho scritto una funzione con nome let myPred (MyCons _) = True; myPred _ = False inma entrambi sembrano terribilmente brutti e non molto idiomatici. Il modo "ovvio" (e sbagliato) sarebbe qualcosa di simile \(MyCons _) -> Truema che genera un errore per essere parziale, naturalmente, e anche allora sembra che ci debba essere un modo più pulito.

C'è un modo più conciso / pulito per fare questo genere di cose? O sto andando sulle cose completamente nel modo sbagliato?


1
Forse questa è una cosa di "gusto personale" ma, se hai bisogno di questo predicato in un solo posto, sarei abbastanza contento della letclausola che non ti piace, anche se preferisco la whereclausola equivalente in modo da non ingombrare la definizione principale. Ovviamente se finisci per aver bisogno di questa utility più di una volta, la definiresti come una funzione di livello superiore.
Robin Zigmond,

Funziona sicuramente bene. La mia domanda è stata in qualche modo motivata da quanto tipicamente succinto sia Haskell. Di solito sembra che l'idiomatico Haskell abbia pochissime duplicazioni di idee e riduca al minimo la lanugine. Quindi non è nemmeno necessariamente che penso che lo let myPred...stile sia cattivo , ma sembra molto più dettagliato di quanto mi aspetterei per un'idea molto semplice, il che mi porta a chiedermi se sto abbaiando sull'albero sbagliato.
David Sampson, il

2
Potresti dare un'occhiata ai prismi (dalla lente). Sono come modelli componibili di prima classe
luqui

1
Penso che dovremmo vedere un esempio di dove stai usando questo tipo di funzione di ordine superiore. Parte di me vuole dire che il problema riguarda innanzitutto il progetto che richiede un simile predicato.
Chepner

il modo Haskell98, per questo, è quello di definire la funzione di corrispondenza dei casi (decostruzione) per il tipo di dati, come maybe :: b -> (a -> b) -> Maybe a -> be bool :: a -> a -> Bool -> a, quindi, usarla con le funzioni che producono booleane come argomenti. ad es. myCons z f (MyCons x) = f x ; myCons z f _ = z, quindi chiama myCons False (const True) aMyConsValue. questo è quasi ciò che hai scritto, ha solo un altro livello di "indiretta" / "astrazione" tramite argomenti funzionali, inserito in esso.
Will Ness,

Risposte:


7

Puoi usare l'estensione di lingua LambdaCase per usare \case MyCons _ -> True; _ -> False, anche se questo non salva così tanti caratteri.

Credo che potresti scrivere una serie di funzioni constructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Boolma non sono abbastanza competente con Generics per implementarlo senza poche ore per testare le cose. Proverò questo e modificherò la mia risposta se riesco a capirlo o se è un vicolo cieco.

EDIT: Sì, puoi farlo! Ecco un link al mio codice, che implementa tutto da zero:

https://repl.it/@lalaithion/ConstructedWith

Tuttavia, utilizzare qualcosa come http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html per tutte le tubature del codice generico potrebbe essere migliore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.