Предположим, у меня есть следующие функции запоминания. (Игнорируйте тот факт, что они чистые, пожалуйста.)
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
дает дополнительную ошибку, заключающуюся в том, что в уравнении нет ограничения Typeable1
.
Не удалось вывести (Typeable1 Eq), возникающий в результате использования `cast' из контекста (Typeable a, Typeable b)
Возможно ли то, чего я хочу достичь, возможно, используя Template Haskell? Или это совсем невозможно и нежелательно уметь делать?
memoEqOrd
? ты не разрешаешь? - person josejuan   schedule 29.05.2013