Я ищу функцию
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
memoC :: (c => a) -> (c => a)
чтобы результат a
оценивался только один раз для поставленного ограничения.
Другая короткая версия
Как я могу сделать значение некоторого типа a
, которое может быть проверено только при наличии доказательства некоторого ограничения c
?
Мотивация
Я давно искал общее решение для запоминания значений формы:
C a => a
Где c
- некоторое ограничение, а a
- диапазоны по всем типам. С ограничением Typeable
на a
и некоторыми интеллектуальными конструкторами можно было бы безопасно memoize позвоночника trie для Typeable a => b
, построив trie over TypeRep
s. Этот вопрос касается более сложной части, что положить в листья такой тройки.
Если мы можем каким-то образом получить a
в листья, у листьев trie сначала должно быть значение C a => a
для определенного типа a
, так как словари для классов не могут быть просмотрены с тип. Для поиска значений из trie потребуется словарь для C a
. Это, по-видимому, означает изменение значения, хранящегося на листе trie на основе переданного в словаре.
Если мы не можем каким-то образом получить a
в листья, у листьев будет еще более страшный тип C a => b
для одного b
, а при предоставлении словаря нам нужно будет доказать, что тип a
(и, следовательно, словарь) можно определить тем, что удерживается в b
, которое не будет более мощным, чем TypeRep
.
Зла
Заманчиво добраться до мешка зла, чтобы построить конструктора, чтобы держаться у листьев три. Изменение значения, хранящегося на листе trie на основе переданного в словаре, не является злым, если для каждого ограничения существует только один словарь.
Любое "решение" этого может быть крайне злым. Я предполагаю, что существует только один словарь для любого ограничения. Reflection give
нам другое зло, которое может построить более одного словаря для ограничения.
Откажитесь от этого зла.
Пример
Следующее не должно (и не делает) memoize результат предоставления ограничения TracedC String
.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
import Debug.Trace (trace)
class TracedC a where
tracedC :: () -> a -- The () argument keeps a from being memoized in the dictionary for `TracedC a`
instance TracedC [Char] where
tracedC _ = trace "tracedC :: String" "Yes"
newtype Memoized c a = Memoized { getMemoized :: c => a }
example :: Memoized (TracedC a) a
example = Memoized (tracedC ())
main = do
let memo = example :: Memoized (TracedC [Char]) String
putStrLn $ getMemoized memo
putStrLn $ getMemoized memo
Выходной сигнал
tracedC :: String
Yes
tracedC :: String
Yes
Решение допускает аналогичный пример, но только оценивает tracedC () :: TracedC [Char] -> String
после вывода только
tracedC :: String
Yes
Yes
Связанные попытки
Карта из типов в значения f a
, которые могут быть использованы в монадической записке с явной стороны эффекты.