2013-08-14 14 views
32

Poiché questi contesti e istanze flessibili non sono disponibili nello standard Haskell, presumo che ci siano potenziali problemi durante l'utilizzo. Quali sono? Possono portare ad alcune ambiguità, indecidibilità, istanze sovrapposte, ecc.?Quali sono le insidie ​​nell'utilizzo di FlexibleContexts e FlexibleInstances?

C'è un similar question che richiede solo circa FlexibleInstances, non FlexibleContexts, ma la risposta dice solo "che è sicuro usarli".

+4

Per quanto ho raccolto, sono solo cose a cui non hanno pensato quando hanno scritto lo standard, ma si sono rivelati utili in modo che GHC li includesse come estensioni. L'ovvia insidia che posso pensare è che il codice scritto usando questi strumenti non funzionerà con altri compilatori. Ma sono sicuro che qualcun altro ne sa di più. – kqr

+0

puoi vedere un esempio in questa [risposta] (http://stackoverflow.com/a/15770150/849891)'s [modifica cronologia] (http://stackoverflow.com/posts/15770150/revisions). Ho [prima fatto qualcosa di sbagliato] (http://stackoverflow.com/revisions/95690635-a708-4c29-a22d-95b23038258d/view-source) (nella versione 1) e sono stato suggerito dal GHCi di aggiungere FlexibleContexts. E ha compilato. (Inizialmente non avevo il vincolo Genome nella classe e w/FlexContxs lo compilava). –

+0

@WillNess Questo è molto difficile da scoprire, potresti dare una risposta basata su di esso? –

risposta

16

Una volta mi sono imbattuto in quanto segue. Answering this question, ho provato questo codice:

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 

class (Eq a, Show a) => Genome a where 
    crossover  :: (Fractional b) => b -> a -> a -> IO (a, a) 
    mutate   :: (Fractional b) => b -> a -> IO a 
    develop   :: (Phenotype b a) => a -> b 

class (Eq a, Show a) => Phenotype a b | a -> b where 
    -- In case of Coevolution where each phenotype needs to be compared to 
    -- every other in the population 
    fitness   :: [a] -> a -> Int 
    genome   :: (Genome b) => a -> b -- here, the problem 

breed parents cross mute = do 
    children <- mapM (\ (dad, mom) -> crossover cross (genome dad) (genome mom)) 
        parents 
    let ch1 = map fst children ++ map snd children 
    mutated <- mapM (mutate mute) ch1 
    return $ map develop mutated 

e ottenuto un errore di compilazione e un suggerimento di GHCi per aggiungere l'opzione FlexibleContexts. Quando l'ho fatto, ha compilato OK. Ma in realtà non era una cosa giusta da fare, poiché la dichiarazione di vincoli ha introdotto un nuovo ambito per le variabili di tipo e b nella firma del tipo genome è diventato completamente non correlato a quello della classe del tipo; ancora FlexibleContexts fornito una copertura per questo.

Con il vincolo specificato correttamente a livello di classe tipo,

class (Eq a, Show a, Genome b) => Phenotype a b | a -> b where 
    -- In case of Coevolution where each phenotype needs to be compared to 
    -- every other in the population 
    fitness   :: [a] -> a -> Int 
    genome   :: a -> b 

passò la compilazione senza richiedere l'opzione FlexibleContexts.

+3

Non era il problema che dichiarando 'genome :: (Genome b) => a -> b' con il vincolo della classe tipo, in realtà ha introdotto una nuova variabile di tipo' b' che ombreggiava quella originale? –

+0

@ PetrPudlák quindi dichiarare un vincolo introduce un nuovo ambito per le variabili di tipo? In tal caso, il metodo del genoma * potrebbe * restituire un tipo di genoma completamente estraneo al tipo di fenotipo a cui apparteneva. Questo sarebbe sicuramente un flusso di progettazione e FlexibleInstances fornirebbe una copertura per esso, giusto? In tal caso, ciò si qualificherebbe per una trappola. :) –

+1

Peccato che "-Wall' non avvisi qui. (Non penso che questo sia un errore ... basta nominare lo shadowing. Detto questo, il codice ha un bug a causa di questo.) –

Problemi correlati