我一直在和封闭式家庭玩耍,但是我总是不知道事情通常情况下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
这编译但我认为第一种情况永远不会匹配这可能是一个错误。
答案 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
请注意,由于等式约束,您仍然需要类型系列扩展名。