使用函数依赖关联的参数限制 [英] Associated Parameter Restriction using Functional Dependency
问题描述
下面的函数f,对于给定的类型'a',采用类型'c'的参数。对于不同类型的'a','c'以不同的方式受到限制。具体来说,当'a'是任何Integral类型时,'c'应该被允许为任何'Real'类型。当'a'是浮动时,'c'只能是浮动。
一次尝试是:
<$ p $ { - #LANGUAGE
MultiParamTypeClasses,
FlexibleInstances,
FunctionalDependencies,
UndecidableInstances# - }
class AllowedParamType ac | a - > c
class Foo a where
f ::(AllowedParamType a c)=> c - > a
fIntegral ::(Integral a,Real c)=> c - > a
fIntegral =错误执行消失
实例(Integral i,AllowedParamType i d,Real d)=> Foo i其中
f = fIntegral
由于某些原因,GHC 7.4.1抱怨它无法推断(实际c)由于使用fIntegral而产生。在我看来,功能依赖应该允许这种推论。在这个例子中,a与i是统一的,所以通过函数依赖,d应该与c一致,在实例中它被声明为'Real'。我在这里错过了什么?
抛开功能依赖关系,这种方法是否足以表达上述限制,还是有更好的方法?我们只处理'a'的一些不同的值,所以会有这样的情况:
instance(Integral i, Real c)=> AllowedParamType ic
实例AllowedParamType Float Float
谢谢
源和目标类型之间的任何关系,而不是存在一个实例:
{ - #LANGUAGE OverlappingInstances,FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses# - }
class Foo ab where f :: a - > b
现在我们可以用 这确实意味着很多显式类型注释以避免 您可以使用标准类型列出所有想要 请注意: mean嘿,如果你有一个整型 这很容易破坏其他实例,所以如果你现在输入 您可以更改您的编译指示以包含OverlappingInstances: 所以现在 我认为这种方法可能适用于您,手动定义多个实例,仔细考虑何时完全通配 The function f below, for a given type 'a', takes a parameter of type 'c'. For different types 'a', 'c' is restricted in different ways. Concretely, when 'a' is any Integral type, 'c' should be allowed to be any 'Real' type. When 'a' is Float, 'c' can ONLY be Float. One attempt is: For some reason, GHC 7.4.1 complains that it "could not deduce (Real c) arising from a use of fIntegral". It seems to me that the functional dependency should allow this deduction. In the instance, a is unified with i, so by the functional dependency, d should be unified with c, which in the instance is declared to be 'Real'. What am I missing here? Functional dependencies aside, will this approach be expressive enough to enforce the restrictions above, or is there a better way? We are only working with a few different values for 'a', so there will be instances like: Thanks OK, this one's been nagging at me. given the wide variety of instances,
let's go the whole hog and get rid of any relationship between the
source and target type other than the presence of an instance: Now we can match up pairs of types with an This does mean a lot of explicit type annotation to avoid You could list all of the instances with the standard types that you want,
which could lead to an awful lot of repetition, our you could light the blue touchpaper and do: Beware: this does not mean "Hey, if you've got an integral type This can easily break your other instances, so if you now type You can change your pragmas to include OverlappingInstances: So now I think this sort of approach might work for you, defining many instances by hand, carefully considering when to go completely wild
making instances out of standard type classes. (Alternatively, there aren't all that many standard types, and as we all know, 这篇关于使用函数依赖关联的参数限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! f $例如:
$ b $ pre $ instance Foo Int Int其中f =(+1)$ b ((7 :: Int) - )
实例Foo Integer Int其中f = fromInteger。(^(2 :: Integer))
实例Foo整数Integer Integer其中f = toInteger。其中f =(* 100)
实例Foo Char Char其中f = id
实例Foo Char字符串其中f =(:[]) - 需要TypeSynonymInstances
实例(Foo ab,Functor f )=> Foo(fa)(fb)其中f = fmap f - 需要FlexibleInstances
实例Foo Float Int其中f = round
实例Foo Integer Char其中fn = head $ show n
没有实例用于...
和不明确的类型
错误消息。
例如,您不能执行 main = print(f 6)
,但您可以执行 main = print(f(6 :: Int):: Int)
这可能导致很多重复,我们可以点亮蓝色的触摸纸,然后做:
实例Integral i => Foo Double i其中f = round - 需要FlexibleInstances
实例Real r => Foo Integer r其中f = fromInteger - 需要FlexibleInstances
i
,
你可以有一个实例 Foo Double i
免费使用这个方便的函数,
表示:每个您有 类型类型 i
,它绝对是一个实例
Foo Double i
。顺便说一句,我使用 round
,因此,除非你的类型 i
是积分
,
,否则我们会下跌去。例如,这对于 Foo Integer Char
实例来说是个大问题。
f(5 :: Integer):: Integer
,你可以得到
Foo整数的重叠实例整数
使用`f'引起
匹配实例:
实例Foo整数整数
实例r => Foo整数r
{ - #LANGUAGE OverlappingInstances,FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses# - }
f(5 :: Integer):: Integer
返回500,很明显它使用更具体的 Foo整数整数
实例。
使用标准类型类实例。 (或者,并非所有标准类型都是这样,我们都知道, notMany选择2 = notIntractablyMany
,因此您可以将它们全部列出。){-# LANGUAGE
MultiParamTypeClasses,
FlexibleInstances,
FunctionalDependencies,
UndecidableInstances #-}
class AllowedParamType a c | a -> c
class Foo a where
f :: (AllowedParamType a c) => c -> a
fIntegral :: (Integral a, Real c) => c -> a
fIntegral = error "implementation elided"
instance (Integral i, AllowedParamType i d, Real d) => Foo i where
f = fIntegral
instance (Integral i, Real c) => AllowedParamType i c
instance AllowedParamType Float Float
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
class Foo a b where f :: a -> b
f
between them however we like, for example:instance Foo Int Int where f = (+1)
instance Foo Int Integer where f = toInteger.((7::Int) -)
instance Foo Integer Int where f = fromInteger.(^ (2::Integer))
instance Foo Integer Integer where f = (*100)
instance Foo Char Char where f = id
instance Foo Char String where f = (:[]) -- requires TypeSynonymInstances
instance (Foo a b,Functor f) => Foo (f a) (f b) where f = fmap f -- requires FlexibleInstances
instance Foo Float Int where f = round
instance Foo Integer Char where f n = head $ show n
No instance for...
and Ambiguous type
error messages.
For example, you can't do main = print (f 6)
, but you can do main = print (f (6::Int)::Int)
instance Integral i => Foo Double i where f = round -- requires FlexibleInstances
instance Real r => Foo Integer r where f = fromInteger -- requires FlexibleInstances
i
,
you can have an instance Foo Double i
for free using this handy round function",
it means: "every time you have any type i
, it's definitely an instance
Foo Double i
. By the way, I'm using round
for this, so unless your type i
is Integral
,
we're going to fall out." That's a big issue for the Foo Integer Char
instance, for example.f (5::Integer) :: Integer
you getOverlapping instances for Foo Integer Integer
arising from a use of `f'
Matching instances:
instance Foo Integer Integer
instance Real r => Foo Integer r
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
f (5::Integer) :: Integer
returns 500, so clearly it's using the more specific Foo Integer Integer
instance.notMany choose 2 = notIntractablyMany
, so you could just list them all.)