我正在尝试扩展(或试图找出是否有可能扩展)一个类型签名的函数,该类型签名已经达到了我的知识范围,因为我使用的库将非常多态的类型和API公开给更多的多态类型和API。
我使用的是persistent和hsqml,这两个库都有非常丰富的类型,至少对我来说是这样。
我需要将persistent实体包装到hsqml“代理”对象中,以便公开给QML (基本上是javascript)。为此,我让自己成为一个名为getStandardClassMembers的帮手。你就这样用它:
instance DefaultClass (Entity Project) where
classMembers = getStandardClassMembers
[
("name", projectName),
("hasCustomIcon", text . not . BS.null . projectIcon),
("hasDev", projectHasDev), -- TODO bool as string, ugly..
("hasUat", projectHasUat),
("hasStaging", projectHasStage),
("hasProd", projectHasProd)
]
[]getStandardClassMembers的定义是那里。它用我指定的成员定义一个javascript对象,并调用我给出的haskell函数来实现JS对象的成员。
这很不错,但是有一个“但是”。对中第二个位置的函数必须返回Text。在这里,除了第一个函数之外,我更愿意返回一个Bool。因此,理想情况下,我会使getStandardClassMembers的类型签名更加多态,而不需要第二个函数返回一个Text。再说一次,我不知道是否可能,但我决定试一试。
因此,我将RankNTypes添加到该文件的大量语言扩展名列表中(由于我选择的库,这些库都很棒),我被迫加入其中。
我改变了:
getStandardClassMembers :: (Marshal tr, ToBackendKey SqlBackend record, Typeable record,
MarshalMode tr ICanReturnTo () ~ Yes) =>
[(String, record -> tr)] -> [(String, ObjRef (Entity record) -> Maybe Int)]
-> [Member (GetObjType (ObjRef (Entity record)))]至:
getStandardClassMembers :: (Marshal tr, ToBackendKey SqlBackend record, Typeable record,
MarshalMode tr ICanReturnTo () ~ Yes) =>
[(String, forall tr. record -> tr)] -> [(String, ObjRef (Entity record) -> Maybe Int)]
-> [Member (GetObjType (ObjRef (Entity record)))](所以我添加了forall tr.),我得到了:
Illegal polymorphic or qualified type: forall tr. record -> tr
Perhaps you intended to use ImpredicativeTypes现在,我对这些事情有了足够的了解,知道启用ImpredicativeTypes不是一个好主意。另外,如果我启用它,它也不起作用。
我想要的是可以实现的,还是应该让它休息一下,并感谢那些已经非常混乱的类型签名和语言扩展集合,任何事情都能奏效呢?
编辑--也许正确的解决方法是忘记我的助手,并使用hsqml basic API返回到基础知识。但除此之外,我仍然很好奇这是否可能。
发布于 2015-07-20 23:09:30
我认为最基本的问题是,您试图将不同类型的值放在一个列表中。即使是ImpredicativeTypes,也不允许您以所需的方式进行此操作。存在主义类型可以使用包装器,但我认为它们也太过分了。
相反,我建议从插入元组改为插入始终是相同类型的东西,这取决于您实际如何使用元组。看看你的链接代码
\(name, f) -> defPropertyConst name (return . f . entityVal . fromObjRef)作为您在元组上使用的函数,可以从元组中获得实际需要的内容。那么,为什么不为此定义一个全局函数呢?
stdMember name f = defPropertyConst name (return . f . entityVal . fromObjRef)(这个名称只是一个建议;您可能需要更短的东西,甚至是一个操作符。)
然后将getStandardClassMembers更改为将此类值的列表作为其第一个参数,而对于第二个参数则可能类似。
假设没有更多的类型微妙之处,那么您应该能够编写
instance DefaultClass (Entity Project) where
classMembers = getStandardClassMembers
[
stdMember "name" projectName,
stdMember "hasCustomIcon" $ text . not . BS.null . projectIcon,
stdMember "hasDev" projectHasDev, -- TODO bool as string, ugly..
stdMember "hasUat" projectHasUat,
stdMember "hasStaging" projectHasStage,
stdMember "hasProd" projectHasProd
]
[]https://stackoverflow.com/questions/31523905
复制相似问题