haskell - 可以在 Strings 和 Int 上调用的函数。模糊类型变量问题
问题描述
我想编写一个可以在数字(例如1
)和字符串(例如"a"
)上调用的函数。在我的应用程序中,尽可能简化“用户代码”很重要。
我的代码的最小示例如下所示
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
type StrInt = Either String Int
class Lift a where
toStrInt :: a -> StrInt
instance Lift String where
toStrInt= Left
instance Lift Int where
toStrInt= Right
declare:: StrInt ->String
declare (Left a) = "String: " ++ a
declare (Right n) = "Number: " ++ (show n)
declare' :: Lift a => a -> String
declare' a = declare (toStrInt a)
myDecA = declare' "a"
myDec1 = declare' 1
编译它会给出错误
Ambiguous type variable ‘a0’ arising from a use of ‘declare'’
prevents the constraint ‘(Lift a0)’ from being solved.
我了解这个问题,并且我知道我可以将最后一行替换为以下任何内容:
myDec1 = declare' (1::Int)
myDec1 = declare (Right 1)
但这违背了我想要达到的目的。有没有一种巧妙的方法来设置相同的想法,从而清楚地表明 1 是一个 Int?
此外,在我的应用程序中(比上面的最小示例更复杂)该declare
函数仅适用于Int
s。所以我不能一概而论Num a
。
解决方案
使用 Haskell 是不可能的。这样做的原因是,虽然1
看起来像Int
,但实际上是Num a => a
。Haskell 没有办法知道这Int
是唯一a
满足的(Num a, Lift a) => a
,所以需要明确地告诉它。例如,如果我在另一个模块中创建以下实例:
instance Num String where
...
然后declare' 1
变得模棱两可,并且可以合理地导致"String:..."
or "Int:..."
。Haskell 在编译时无法知道我不会这样做,所以我们遇到了问题。
推荐阅读
- ruby-on-rails - 如何使用 Nokogiri 按子节点值搜索 XML 节点的值?
- node.js - Sails js中的MaxListenersExceededWarning
- c# - 数据网格视图中的添加
- api - twitter api中的速率限制
- hyperledger-fabric - 为不同的超级账本作曲家身份使用不同的 REST 客户端
- python - VsCode中的python模块管理
- php - 处理时遇到错误:systemd
- azure - 我可以为 Azure Functions 应用设置特定时区吗?
- python-3.x - 用于大型终端的 ncurses(用于 python)的鼠标支持
- mysql - 如何在 SQL 中的三个或更多表之间进行 Group By