(其他一些 mtl monad 也会带来同样的问题,但我们只用
Reader
来举例说明)
假设我需要以人类可读的方式显示某些内容,其中实现和行为细节取决于用户偏好,从配置中读取:
showIt :: Config -> Object -> String
如果用户配置只是读取而不是修改,那么不妨使用
Reader
来反映这一点:
showIt :: Reader Config (Object -> String)
但是等等,这和这个有什么不同:
showIt :: Object -> Reader Config String
虽然我几乎不知道
Reader
,但我确实尝试过这两种设计,而且它们看起来功能相同。我仍然想知道两者之间是否存在语义差异,也就是说,当其他一些 Haskellers 查看我的代码时,如果我使用其他设计,他们会解释不同的目的或含义吗?
如果是这样,那么在这种情况下应该首选哪种用法?
与Reader Config (Object -> String)
有什么不同?Object -> Reader Config String
前者将
showIt
实现限制为 read
一次配置,然后生成一个必须适用于所有对象的字符串转换函数。后者允许实现根据输入对象决定读取什么配置(或者更确切地说,是否读取1)。
他们的使用模式有很大不同:
do
showAny <- showIt
let str1 = showAny object1
let str2 = showAny object2
return (str1 ++ " " ++ str2)
对
do
let show1 = showIt object1
let show2 = showIt object2
str1 <- show1
str2 <- show2
return (str1 ++ " " ++ str2)
1:使用
Reader
monad,没有太多选择 - 你只能决定是否读取配置(或者:多久读取一次 - 但每次都是一样的)。对于其他 monad,读取配置的不同位可能涉及不同的文件系统或数据库访问等,差异会变得更大。