具有约束参数函数的类型类
typeclass with constrained params' function
我想写一个class这样的:
class C c where
op :: c -> c -> Bool
class A b => B b where
func :: C c => b -> c -- ^ type 'c' is random(forall).
func2 :: b -> b -> Bool
func2 x y = func b `op` func c
这里,c
是被C
限制的类型,这个限制会用在func2中。
但这不能是编译器。类型 c
不是真实类型。我尝试添加 forall
或使用 TypeFamilies
,但其中 none 可以做到这一点。 TypeFamilies
看起来不错,但它不能在像 C c => b -> c
或 `type X x :: C * => *.
这样的函数定义中使用 with restriction
我必须使用(A b, C c) => B b c
来定义这个class吗?我有另一个 class 与 B 一起使用,例如 B b => D d b
。如果为 class B 添加一个参数,则 D class 也需要一个参数。实际上Seq a
会和classD
一起使用,不能匹配D d b
.
编辑:再写一篇。
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Main where
type Ta = (Integer, Integer)
newtype Tb t = Tb { tb :: [t] } deriving Show
class Eq a => A a where
a1f :: Ord b => a -> b
a2f :: a -> a -> Bool
a2f x y = a1f x >= a1f y
instance A Ta where
a1f (_, y) = y
class A a => B b a where
op :: b a -> b a
instance B Tb Ta where
op x = x
main :: IO ()
main = putStrLn $ show $ op $ (Tb [(1, 1)] :: Tb Ta)
编译器会报错 a2f :: b -> Bool
:
• Could not deduce (Ord a0) arising from a use of ‘>=’
from the context: A a
bound by the class declaration for ‘A’ at test.hs:10:15
The type variable ‘a0’ is ambiguous
These potential instances exist:
instance Ord Ordering -- Defined in ‘GHC.Classes’
instance Ord Integer
-- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’
instance Ord a => Ord (Maybe a) -- Defined in ‘GHC.Maybe’
...plus 22 others
...plus four instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: a1f x >= a1f y
In an equation for ‘a2f’: a2f x y = a1f x >= a1f y
EDIT2:使用类型族
...
class Eq a => A a where
type AT a :: *
a1f :: Ord (AT a) => a -> AT a
a2f :: a -> a -> Bool
a2f x y = a1f x >= a2f y
instance A Ta where
type AT Ta = Integer
a1f (_, y) = y
...
它将显示错误:
• Could not deduce (Ord (AT a)) arising from a use of ‘>=’
from the context: A a
bound by the class declaration for ‘A’ at test.hs:10:15
• In the expression: a1f x >= a1f y
In an equation for ‘a2f’: a2f x y = a1f x >= a1f y
在您的代码中,问题很简单,func b `op` func c
中的 c
是 不明确的 。这并不是什么大问题:只需用本地签名确定选择即可。例如
func2 x y = func x `op` (func y :: Int)
但这可能不是您真正想要的。 c
真的应该是 func
class 或整个实例的类型参数吗?在后一种情况下,MPTC 将是正确的方法。
{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes, TypeApplications #-}
class ∀ b c . (A b, C c) => B b c where
func :: b -> c
func2 :: b -> b -> Bool
func2 x y = func @b @c b `op` func c
或者如果对于每个实例,只有一个 c
有意义,那么您需要一个类型系列或 fundep。
{-# LANGUAGE TypeFamilies #-}
class A b => B b where
type Ct b :: *
func :: b -> Ct b
func2 :: b -> b -> Bool
func2 x y = func b `op` func c
对您的类型族代码进行编译的最小修复是将对 Ord
约束的需求从生成它的地方转移到使用它的地方:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstrainedClassMethods #-}
type Ta = (Integer, Integer)
class Eq a => A a where
type AT a :: *
a1f :: a -> AT a
a2f :: Ord (AT a) => a -> a -> Bool
a2f x y = a1f x >= a1f y
instance A Ta where
type AT Ta = Integer
a1f (_, y) = y
如果您只想在使用默认实现时要求 Ord (AT a)
,您可以使用 DefaultSignatures
(并删除 ConstrainedClassMethods
):
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DefaultSignatures #-}
type Ta = (Integer, Integer)
class Eq a => A a where
type AT a :: *
a1f :: a -> AT a
a2f :: a -> a -> Bool
default a2f :: Ord (AT a) => a -> a -> Bool
a2f x y = a1f x >= a1f y
instance A Ta where
type AT Ta = Integer
a1f (_, y) = y
但是,这种class结构非常奇怪和不合常理。 (当我阅读它时,它引发了一些危险信号:那个 Eq
约束在那里做什么?为什么只有一个实例有一个 class?为什么 a2f
在 class 而不是外部?为什么 a1f
不是一个非 class 多态函数?为什么我们应该相信每种类型只有一个规范选择函数?)
我想重申,你应该告诉我们更多关于你试图通过此实现的目标,而不是谈论你提议的类型class es 实现该目标。关于此架构的很多内容令人尖叫 "beginner trying to use typeclasses the way OO languages use classes",这将成为阻抗不匹配和剪纸的持续来源。我强烈怀疑你根本不应该定义一个新类型class。
我想写一个class这样的:
class C c where
op :: c -> c -> Bool
class A b => B b where
func :: C c => b -> c -- ^ type 'c' is random(forall).
func2 :: b -> b -> Bool
func2 x y = func b `op` func c
这里,c
是被C
限制的类型,这个限制会用在func2中。
但这不能是编译器。类型 c
不是真实类型。我尝试添加 forall
或使用 TypeFamilies
,但其中 none 可以做到这一点。 TypeFamilies
看起来不错,但它不能在像 C c => b -> c
或 `type X x :: C * => *.
我必须使用(A b, C c) => B b c
来定义这个class吗?我有另一个 class 与 B 一起使用,例如 B b => D d b
。如果为 class B 添加一个参数,则 D class 也需要一个参数。实际上Seq a
会和classD
一起使用,不能匹配D d b
.
编辑:再写一篇。
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Main where
type Ta = (Integer, Integer)
newtype Tb t = Tb { tb :: [t] } deriving Show
class Eq a => A a where
a1f :: Ord b => a -> b
a2f :: a -> a -> Bool
a2f x y = a1f x >= a1f y
instance A Ta where
a1f (_, y) = y
class A a => B b a where
op :: b a -> b a
instance B Tb Ta where
op x = x
main :: IO ()
main = putStrLn $ show $ op $ (Tb [(1, 1)] :: Tb Ta)
编译器会报错 a2f :: b -> Bool
:
• Could not deduce (Ord a0) arising from a use of ‘>=’
from the context: A a
bound by the class declaration for ‘A’ at test.hs:10:15
The type variable ‘a0’ is ambiguous
These potential instances exist:
instance Ord Ordering -- Defined in ‘GHC.Classes’
instance Ord Integer
-- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’
instance Ord a => Ord (Maybe a) -- Defined in ‘GHC.Maybe’
...plus 22 others
...plus four instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: a1f x >= a1f y
In an equation for ‘a2f’: a2f x y = a1f x >= a1f y
EDIT2:使用类型族
...
class Eq a => A a where
type AT a :: *
a1f :: Ord (AT a) => a -> AT a
a2f :: a -> a -> Bool
a2f x y = a1f x >= a2f y
instance A Ta where
type AT Ta = Integer
a1f (_, y) = y
...
它将显示错误:
• Could not deduce (Ord (AT a)) arising from a use of ‘>=’
from the context: A a
bound by the class declaration for ‘A’ at test.hs:10:15
• In the expression: a1f x >= a1f y
In an equation for ‘a2f’: a2f x y = a1f x >= a1f y
在您的代码中,问题很简单,func b `op` func c
中的 c
是 不明确的 。这并不是什么大问题:只需用本地签名确定选择即可。例如
func2 x y = func x `op` (func y :: Int)
但这可能不是您真正想要的。 c
真的应该是 func
class 或整个实例的类型参数吗?在后一种情况下,MPTC 将是正确的方法。
{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes, TypeApplications #-}
class ∀ b c . (A b, C c) => B b c where
func :: b -> c
func2 :: b -> b -> Bool
func2 x y = func @b @c b `op` func c
或者如果对于每个实例,只有一个 c
有意义,那么您需要一个类型系列或 fundep。
{-# LANGUAGE TypeFamilies #-}
class A b => B b where
type Ct b :: *
func :: b -> Ct b
func2 :: b -> b -> Bool
func2 x y = func b `op` func c
对您的类型族代码进行编译的最小修复是将对 Ord
约束的需求从生成它的地方转移到使用它的地方:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstrainedClassMethods #-}
type Ta = (Integer, Integer)
class Eq a => A a where
type AT a :: *
a1f :: a -> AT a
a2f :: Ord (AT a) => a -> a -> Bool
a2f x y = a1f x >= a1f y
instance A Ta where
type AT Ta = Integer
a1f (_, y) = y
如果您只想在使用默认实现时要求 Ord (AT a)
,您可以使用 DefaultSignatures
(并删除 ConstrainedClassMethods
):
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DefaultSignatures #-}
type Ta = (Integer, Integer)
class Eq a => A a where
type AT a :: *
a1f :: a -> AT a
a2f :: a -> a -> Bool
default a2f :: Ord (AT a) => a -> a -> Bool
a2f x y = a1f x >= a1f y
instance A Ta where
type AT Ta = Integer
a1f (_, y) = y
但是,这种class结构非常奇怪和不合常理。 (当我阅读它时,它引发了一些危险信号:那个 Eq
约束在那里做什么?为什么只有一个实例有一个 class?为什么 a2f
在 class 而不是外部?为什么 a1f
不是一个非 class 多态函数?为什么我们应该相信每种类型只有一个规范选择函数?)
我想重申,你应该告诉我们更多关于你试图通过此实现的目标,而不是谈论你提议的类型class es 实现该目标。关于此架构的很多内容令人尖叫 "beginner trying to use typeclasses the way OO languages use classes",这将成为阻抗不匹配和剪纸的持续来源。我强烈怀疑你根本不应该定义一个新类型class。