Определение реализации метода на основе доступных ограничений

Предположим, у меня есть следующие функции запоминания. (Игнорируйте тот факт, что они чистые, пожалуйста.)

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? Или это совсем невозможно и нежелательно уметь делать?


person Alessandro Vermeulen    schedule 29.05.2013    source источник
comment
Что произойдет, если memoEqOrd? ты не разрешаешь?   -  person josejuan    schedule 29.05.2013
comment
@josejuan: Это не было бы проблемой, я бы выбрал memoOrd или memoEq. Предположим, что есть заказ по функциям мемо, но какой именно сейчас не важно, я чувствую.   -  person Alessandro Vermeulen    schedule 29.05.2013


Ответы (1)


В реализации классов типов GHC (и вообще) невозможно искать словари классов во время выполнения. Алгоритм генерации словарного кода встроен в механизм вывода типов компилятора, и ни в одном коде времени выполнения нет соответствующего алгоритма. Насколько я знаю, нет базы данных времени выполнения всех экземпляров класса, которая вам понадобится для реализации этого алгоритма. Принцип разработки, лежащий в основе этого, заключается в том, что типы не являются данными, поэтому программа не может их проверять.

Более того, невозможно выбрать наилучший метод мемоизации во время компиляции, потому что система классов типов позволяет определять новые экземпляры. Поскольку вы не можете доказать, что тип не является членом Hashable — возможно, определение экземпляра находится в файле, который еще не был скомпилирован, — вы не можете исключить возможность того, что какой-либо данный тип тип следует запоминать на основе класса Hashable; то же самое касается Eq и Ord.

Я думаю, что лучшим решением будет вручную выбрать способ запоминания каждого типа, написав Memo экземпляров для каждого конструктора типа.

person Heatsink    schedule 29.05.2013
comment
Четкий и краткий ответ, а также о времени выполнения и битах типов. - person Alessandro Vermeulen; 30.05.2013