【问题标题】:What are the pitfalls of using FlexibleContexts and FlexibleInstances?使用 FlexibleContexts 和 FlexibleInstances 有哪些陷阱?
【发布时间】:2013-08-14 10:41:34
【问题描述】:

由于这些灵活的上下文和实例在 Haskell 标准中不可用,我认为在使用它们时存在潜在问题。这些是什么?它们会导致一些歧义、不可判定性、重叠实例等吗?

有一个similar question 只询问FlexibleInstances,而不是FlexibleContexts,但答案只说“使用它们是安全的”。

【问题讨论】:

  • 据我所知,它们只是他们在编写标准时没有考虑到的东西,但事实证明它们很有用,因此 GHC 将它们作为扩展包含在内。我能想到的明显缺陷是使用它们编写的代码不能与其他编译器一起使用。但我相信其他人知道的更多。
  • 您可以在answeredit history 中看到一个示例。我first did something wrong(在修订版 1 中)并得到 GHCi 的建议添加 FlexibleContexts。它编译。 (我一开始在课堂上根本没有基因组约束,而是用 FlexContxs 编译的)。
  • @WillNess 这个很难发现,能不能给个答案?

标签: haskell ghc language-extension


【解决方案1】:

我曾经偶然发现以下内容。 Answering this question,我先试了这段代码:

{-# 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 选项。当我这样做时,它编译好。但这实际上不是正确的做法,因为约束声明为类型变量引入了新的作用域,并且genome 的类型签名中的b 与类型类中的签名完全无关;然而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 选项的情况下通过了编译。

【讨论】:

  • 问题不是通过使用类型类约束声明genome :: (Genome b) =&gt; a -&gt; b,实际上引入了一个新的类型变量b,它覆盖了原来的变量吗?
  • @PetrPudlák 所以声明一个约束会为类型变量引入新的作用域?在这种情况下,基因组方法可能返回与其所属的表型类型完全无关的基因组类型。这肯定是一个设计流程,FlexibleInstances 会为其提供掩护,对吧?那确实有资格陷入困境。 :)
  • 太糟糕了-Wall 在这里没有警告。 (我不认为这是一个错误......只是名称阴影。也就是说,代码因此存在错误。)
  • @ThomasEding 是的,“这实际上是 [done] in 错误”,即这是一个设计错误(不是 an 实际代码错误),这就是我的意思。对不起,不必要的神秘。 :) 谢谢。
  • 任何解释为什么FlexibleContexts 消除了错误?换句话说:FlexibleContexts 是否只允许这种阴影?为什么你认为没有扩展名是非法的?
猜你喜欢
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 2015-07-07
  • 1970-01-01
  • 2012-06-05
  • 2021-03-13
  • 2013-07-30
相关资源
最近更新 更多