What are the pitfalls of using FlexibleContexts and FlexibleInstances?

隐身守侯 提交于 2019-12-03 01:03:33
Will Ness

I once stumbled upon the following. Answering this question, I first tried this code:

{-# 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

And got a compilation error and a suggestion by GHCi to add the FlexibleContexts option. When I did, it compiled OK. But this was actually not a right thing to do, as the constraint declaration introduced new scope for type variables, and b in genome's type signature became completely unrelated to the one in the type class; yet FlexibleContexts provided a cover for this.

With the constraint specified properly at the type class level,

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

it passed compilation without requiring the FlexibleContexts option.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!