Прежде всего, я бы настоятельно рекомендуем вам просто предоставить все Необходимые наблюдаемые экземпляры. Вы можете использовать DrIFT, который поддерживает Observable напрямую, или Derive, чтобы автоматически выводить экземпляры, поэтому вам не нужно писать их самостоятельно.
Альтернативы менее острые.
unshow :: Unshow a => String -> a
Это обеспечивается классом Read
. Единственная операция - read
, которая имеет именно тот тип, который вы даете. Функции read
и show
должны быть обратными, так что read . show
эквивалентно id
. Большинство стандартных типов данных предоставляют Read
, хотя сторонние библиотеки могут не работать.
Это будет намного менее эффективно, чем экземпляр Observable, потому что вы будете десериализовать все свои данные каждый раз, когда вы его наблюдаете. Если у вас есть данные любого значительного размера, это будет большим хитом.
Другой альтернативой является создание экземпляра Observable для каждого типа.
instance Show a => Observable a where
observer my = send (show my) (return my)
Опять же, это не значит «Когда„а“является членом шоу, используйте этот Observable экземпляр.» Это означает «Использовать этот экземпляр Observable для всего, и это ошибка, если нет экземпляра Show в области видимости». Это требует много отрывочных расширений и приводит к проблемам с перекрывающимися экземплярами.
Если вы позаботились о том, чтобы использовать капюшон, я не понимаю, почему вы хотели бы иметь этот экземпляр.
Edit:
Оказывается, что преобразование типа имеет более высокий приоритет, чем функции применения: putStrLn . show $ read "Foo"::MyData -- error putStrLn . show $ (read "Foo"::MyData)
Это довольно распространенная проблема.Рассмотрим функцию:
f1 :: String -> String
f1 = show . read
GHC этого не допустит. read :: Read a => String -> a
и show :: Show a => a -> String
, , но когда вы объединяете два, GHC не может понять, какой тип для создания переменной типа a
. Другими словами, у вас есть строка, вы десериализируете ее, а затем повторно сериализуете ее, но какой тип вы десериализируете? Вы должны сообщить GHC, используя явную подпись типа для чтения или показа, что и делает ваш второй пример. Это не преобразование типа, это то, что вы написали код, который не может найти без помощи.
Как насчет чего-то вроде «watchShow :: Show a => String -> a -> a», который заставляет «(показать мой)», но возвращает только «мой» и только когда «мой» на самом деле используется –
Я неправильно понял ранее, предыдущий комментарий удален. Как насчет этой функции 'observShow a = send (показать a) (return a)'? Непроверенный, но он должен работать. –
Конечно, он будет работать, только если вы можете вызвать функцию напрямую, если вам нужен экземпляр Observable. –