我正在使用Rasa,我的文本编辑器,我正在使用Yi.Rope进行大部分低级文本操作,但我想为人们提供一个更好的界面开发扩展。我没有限制人们使用绳索,字符串或文本,而是想到为什么不让人们使用他们想要的任何东西?所以我编写了这个类型类,它允许使用Text的公分母在文本类型之间移动:
import Control.Lens
import qualified Yi.Rope as Y
import qualified Data.Text as T
class TextLike a where
toText :: a -> T.Text
fromText :: T.Text -> a
asText :: Iso' a T.Text
asText = iso toText fromText
instance TextLike Y.YiString where
toText = Y.toText
fromText = Y.fromText
instance TextLike T.Text where
toText = id
fromText = id
instance TextLike [Char] where
toText = T.pack
fromText = T.unpack
textConvert :: (TextLike a, TextLike b) => a -> b
textConvert = fromText . toText
现在我的外部api函数可以使用约束:myFunc :: TextLike a => a -> ...
约束并在里面调用textConvert
来将任何TextLike转换为任何TextLike。这实际上工作得很好,但是因为我的内部使用了YiString结构而且中间是Text;任何时候我使用这种技术调用函数我从YiString转换为YiString,但textConvert的实现实际上是将YiString转换为Text,然后Text返回YiString,这显然效率低下:P
我喜欢保持类似的普遍性(无论最好的方式是什么);但我想优化某些情况,特别是特殊情况textConvert :: YiString -> YiString
。有人知道一个好方法吗?也许类型级编程,可能是一个完全不同的方法?
谢谢!
答案 0 :(得分:4)
我还没有测试过,但您应该可以使用重写规则进行此优化:
textConvert :: (TextLike a, TextLike b) => a -> b
textConvert = fromText . toText
{-# INLINE [1] textConvert #-}
{-# RULES
"toTextY/fromTextY" forall x. textConvert (x :: Y.YiString) = x
#-}
这将有效地取代所有低效转换。您可以稍后通过使用-ddump-rule-firings
标志进行验证来验证此规则是否会触发。以下是有关重写规则的所有详细信息的教程:https://wiki.haskell.org/GHC/Using_rules