Каковы подводные камни в использовании FlexibleContexts и FlexibleInstances?
Поскольку эти гибкие контексты и экземпляры недоступны в стандарте Haskell, я предполагаю, что при их использовании возможны проблемы. Кто они такие? Могут ли они привести к некоторой двусмысленности, неразрешимости, частичным совпадениям и т. Д.?
Есть похожий вопрос, который задает только о FlexibleInstances
не FlexibleContexts
, но ответ только говорит, что "их можно использовать безопасно".
1 ответ
Однажды я наткнулся на следующее. Отвечая на этот вопрос, я сначала попробовал этот код:
{-# 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
И получил ошибку компиляции и предложение от GHCi добавить FlexibleContexts
вариант. Когда я это сделал, все было в порядке. Но это было на самом деле неправильно, так как объявление ограничения вводило новую область видимости для переменных типа, и b
в genome
сигнатура типа стала совершенно не связана с сигнатурой класса; еще FlexibleContexts
предоставил прикрытие для этого.
С ограничением, заданным правильно на уровне класса типов,
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
он прошел компиляцию, не требуя FlexibleContexts
вариант.