重叠/非相干闭合型家庭

时间:2014-03-13 20:02:01

标签: haskell types

我一直在和封闭式家庭玩耍,但是我总是不知道事情通常情况下Num没有指定类型的事情。

这是一个例子。

{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE DataKinds                 #-}
{-# LANGUAGE UndecidableInstances      #-}
{-# LANGUAGE OverlappingInstances      #-}
{-# LANGUAGE IncoherentInstances       #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module Main where

import Data.Typeable

type family UnMaybed a where
    UnMaybed (Maybe a) = a
    UnMaybed a = a

class UnMaybe x where
    unMaybe :: x -> UnMaybed x

instance UnMaybe (Maybe a) where
    unMaybe (Just a) = a

instance (UnMaybed a ~ a) => UnMaybe a where
    unMaybe a = a

main = do
    print $ unMaybe 'c'
    print $ unMaybe (1::Int)
    print $ unMaybe (Just 1)
    print $ unMaybe 1 -- this line does not compile

除最后一行之外的所有内容都将编译。

../Example.hs:23:17:
    Occurs check: cannot construct the infinite type: s0 ~ UnMaybed s0
    The type variable ‘s0’ is ambiguous
    In the second argument of ‘($)’, namely ‘unMaybe 1’
    In a stmt of a 'do' block: print $ unMaybe 1

现在我知道这是因为数字是多态的,(Maybe a)可能是Num的一个实例。我认为对于正常的重叠类型类,这种困境可以通过使用IncoherentInstances PRAGMA来解决。无论如何,我想问一下是否有办法在类型系列中使这个工作?

我还考虑过在Num

中明确指定UnMaybed
type family UnMaybed a where
    unMaybed (Num a => a) = a
    UnMaybed (Maybe a) = a
    UnMaybed a = a

这编译但我认为第一种情况永远不会匹配这可能是一个错误。

1 个答案:

答案 0 :(得分:1)

回答:http://www.haskell.org/pipermail/haskell-cafe/2014-March/113153.html

这是封闭式家庭的限制,但有充分理由限制。

IncoherentInstances威胁类型类实例的一致性,这意味着约束UnMaybe <<some type>>可能在不同的地方以不同的方式实现,即使对于相同的<<some type>>也是如此。但是,类型类实例选择纯粹是运行时行为效果。选择其他实例不会影响程序中的类型。

另一方面,

类型族直接影响类型。允许像IncoherentInstances一样工作的不连贯性可以用来实现unsafeCoerce。

没有类型签名,没有多少方法可以解决问题。 (一种可能性是使用RebindableSyntax基本上禁用数字重载,但这有点大锤。)

最后一个例子(使用UnMaybed(Num a =&gt; a))甚至编译的事实很快就会出现错误。

<强>修订

我发现你实际上可以实现没有类型系列的这个函数,如下所示。

{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances      #-}
{-# LANGUAGE IncoherentInstances       #-}
{-# LANGUAGE TypeFamilies #-}
module Main where

class UnMaybe x y where
    unMaybe :: x -> y

instance (a~a') => UnMaybe (Maybe a) a' where
    unMaybe (Just a) = a

instance (a~a') => UnMaybe a a' where
    unMaybe a = a

请注意,由于等式约束,您仍然需要类型系列扩展名。