Come comporre `not` con una funzione di arbitrarietà arbitraria?

Quando ho una qualche funzione di tipo

f :: (Ord a) => a -> a -> Bool fab = a > b 

Mi piacerebbe creare una funzione che avvolga questa funzione con no.

per esempio, fai una funzione come questa

 g :: (Ord a) => a -> a -> Bool gab = not $ fab 

Posso fare combinatore come

 nf = (\a -> \b -> not $ fab) 

Ma non so come.

 *Main> let nf = (\a -> \b -> not $ fab) n :: (t -> t1 -> Bool) -> t -> t1 -> Bool Main> :tnf nf :: (Ord t) => t -> t -> Bool *Main> let g = nf g :: () -> () -> Bool 

Che cosa sto facendo di sbagliato?

E domanda bonus come posso farlo per funzionare con più parametri e per non es

 t -> Bool t -> t1 -> Bool t -> t1 -> t2 -> Bool t -> t1 -> t2 -> t3 -> Bool 

A meno che tu non voglia andare a frugare con le classificazioni, che è meglio lasciarlo per esperimenti mentali e prove di concetto, non devi generalizzare a più argomenti. Non provarci

Per quanto riguarda la tua domanda principale, questa è più elegantemente risolta con i combinatori di editor semantico di Conal Elliott. Un combinatore di editor semantico è una funzione con un tipo come:

 (a -> b) -> F(a) -> F(b) 

Dove F(x) è una espressione che coinvolge x . Ci sono anche combinatori di editor “controvarianti” che prendono invece un (b -> a) . Intuitivamente, un combinatore di editor seleziona una parte di un valore più grande su cui operare. Quello di cui hai bisogno si chiama result :

 result = (.) 

Guarda il tipo di espressione su cui stai cercando di operare:

 a -> a -> Bool 

Il risultato (codominio) di questo tipo è a -> Bool , e il risultato di quel tipo è Bool , ed è quello che stai cercando di applicare not a. Quindi, per applicare not al risultato del risultato di una funzione f , scrivi:

 (result.result) not f 

Questo magnificamente si generalizza. Ecco alcuni altri combinatori:

 argument = flip (.) -- contravariant first f (a,b) = (fa, b) second f (a,b) = (a, fb) left f (Left x) = Left (fx) left f (Right x) = Right x ... 

Quindi se hai un valore x di tipo:

 Int -> Either (String -> (Int, Bool)) [Int] 

E tu vuoi candidarti not al Bool, devi solo precisare il percorso per arrivarci:

 (result.left.result.second) not x 

Oh, e se sei già arrivato a Functors, noterai che fmap è un combinatore di editor. In realtà, quanto sopra può essere scritto:

 (fmap.left.fmap.fmap) not x 

Ma penso che sia più chiaro usare i nomi espansi.

Godere.

In realtà, fare arbitrarietà con classi di tipi risulta incredibilmente facile:

 module Pred where class Predicate a where complement :: a -> a instance Predicate Bool where complement = not instance (Predicate b) => Predicate (a -> b) where complement f = \a -> complement (fa) -- if you want to be mysterious, then -- complement = (complement .) -- also works ge :: Ord a => a -> a -> Bool ge = complement (<) 

Grazie per aver segnalato questo interessante problema. Amo Haskell.

Il tuo n combinatore può essere scritto:

 n = ((not .) .) 

Per quanto riguarda la tua domanda bonus, il modo più tipico sarebbe creare molti di questi:

 lift2 = (.).(.) lift3 = (.).(.).(.) lift4 = (.).(.).(.).(.) lift5 = (.).(.).(.).(.).(.) 

eccetera.

Ri: Cosa sto facendo di sbagliato? :

Penso che il tuo combinatore funzioni bene, ma quando lo leghi al livello più alto, una delle fastidiose “regole di default” di Haskell entra in gioco e l’associazione non è generalizzata:

 Prelude> :ty (nf) (nf) :: (Ord t) => t -> t -> Bool Prelude> let g = nf Prelude> :ty g g :: () -> () -> Bool 

Penso che potresti essere sbalordito dalla “restrizione del monomorfismo” in quanto si applica alle classi di tipi. In ogni caso, se esci dal ciclo di primo livello e metti le cose in un file separato con una firma di tipo esplicita, tutto funziona correttamente:

 module X where nf = (\a -> \b -> not $ fab) fab = a > b g :: Ord a => a -> a -> Bool g = nf 

Domanda bonus : per fare questo con un numero sempre maggiore di parametri di tipo, puoi provare a giocare gli scherzi dello scorbuto con il sistema di class tipo. Due documenti da consultare sono la relazione di Hughes e Claessen su QuickCheck e il libro di Ralf Hinze, Generics for the Masses .