假设我必须执行以下记忆功能。 (请忽略它们纯粹的事实。)
memoEq :: Eq a => (a -> b) -> a -> b
memoOrd :: Ord a => (a -> b) -> a -> b
memoHash :: Hashable a => (a -> b) -> a -> b
现在我想要一个允许我选择上述三个备忘录函数中“最佳”的构造。基本上做以下事情的东西:
memo f = case constraint_of_typevar_a_in f of
Eq a -> memoEq
Ord a -> memoOrd
Hashable a -> memoHash
你可以尝试使用类型类,但是你会得到重叠的实例:
class Memo a where
memo :: (a -> b) -> a -> b
instance Eq a => Memo a where
memo = memoEq
instance Ord a => Memo a where
memo = memoOrd
我还尝试使用cast
来检索约束。我意识到这会在运行时发生,正如我在#haskell被告知的那样,这可能是一个坏主意。 (为简洁起见,我省略了memoOrd
和memoHash
的案例。)
{-# LANGUAGE ImpredicativeTypes, ScopedTypeVariables #-}
module Main where
import Data.Typeable
memo :: forall a b. (Typeable a, Typeable b) => (a -> b) -> Maybe (a -> b)
memo f =
let eqf = cast f :: Eq a => Maybe (a -> b)
in case eqf of
Just eqf' -> Just $ memoEq eqf'
Nothing -> Nothing
memoEq :: Eq a => (a -> b) -> a -> b
memoEq = undefined
memoOrd :: Ord a => (a -> b) -> a -> b
memoOrd = undefined
此代码生成以下错误消息:
cast.hs:8:19:
Could not deduce (Eq a) arising from an expression type signature
from the context (Typeable a, Typeable b)
bound by the type signature for
memo :: (Typeable a, Typeable b) => (a -> b) -> Maybe (a -> b)
at cast.hs:6:9-74
Possible fix:
add (Eq a) to the context of
the type signature for
memo :: (Typeable a, Typeable b) => (a -> b) -> Maybe (a -> b)
In the expression: cast f :: Eq a => Maybe (a -> b)
In an equation for `eqf': eqf = cast f :: Eq a => Maybe (a -> b)
In the expression:
let eqf = cast f :: Eq a => Maybe (a -> b)
in
case eqf of {
Just eqf' -> Just $ memoEq eqf'
Nothing -> Nothing }
在Eq a
内移动Maybe
约束会产生一个额外错误,即Eq上没有Typeable1
约束。
无法推断(Typeable1 Eq)因使用`cast'而产生 从上下文(Typeable a,Typeable b)
我想要实现的目标是什么,也许是使用Template Haskell?或者完全不可能也不可能做到这一点?
答案 0 :(得分:12)
在GHC的类型类实现中(通常),不可能在运行时查找类字典。用于生成字典代码的算法被集成到编译器的类型推理引擎中,并且在任何运行时代码中都没有相应的算法。据我所知,没有所有类实例的运行时数据库,为了实现该算法,您需要它。这背后的设计原则是类型不是数据,因此程序无法检查它们。
此外,在编译时无法选择最佳的memoization方法,因为类型类系统允许定义新的实例。因为您无法证明某个类型不是Hashable
的成员 - 也许实例定义位于尚未编译的文件中 - 您无法排除应该根据Hashable
类记忆任何给定类型的可能性;同样适用于Eq
和Ord
。
我认为最好的解决方案是通过为每个类型构造函数编写Memo
实例来手动选择每种类型的记忆方式。