对不起,如果这个问题很基本的话,我对Haskell还很陌生。假设我有一个函数只能处理黄金比率(1.618)中的两个数字,我如何定义myfun y的类型以只取黄金比率数字。如果我在程序中调用我的程序中没有黄金比率的数字(编译错误),会发生什么?如果没有黄金比率号的调用是通过用户输入在运行时进行的,会发生什么情况?
发布于 2010-07-10 18:21:33
您可能需要一个只能用黄金比率数字构造的ADT,然后编写myfun来接受该数据类型。
我假设Integer是一个基本类型,但您可以使用其他类型(例如: Double或Float),甚至可以是多态的。
1)制定ADT
module Golden (Gold, getGold, buildGold) where
data Gold = G Integer Integer
getGold :: Gold -> (Integer, Integer)
getGold (G x y) = (x, y)
buildGold :: Integer -> Integer -> Maybe Gold
buildGold x y
| isGolden x y = Just (G x y)
| otherwise = Nothing注意,这个模块导出Gold类型,但不导出构造函数(即不导出G)。因此,获得Gold类型值的唯一方法是使用buildGold执行运行时检查--但只执行一次--这样所有消费者都可以不用检查就使用黄金值,并将其假定为黄金比率。
2)使用ADT构建myfun
myfun :: Gold -> ???
myfun g = expr
where (x, y) = getGold g现在,如果您尝试使用一个非黄金数字(一个不是myfun类型的值)调用Gold,那么您将得到一个编译时错误。
要构建黄金数字,必须使用Recap函数buildGold函数,这将强制检查数字。
注意什么时候会被检查!您有一个编译时间保证myfun和您想要与Gold一起使用的所有其他函数总是被提供黄金比率。程序输入(来自用户、网络或任何地方)仍然需要运行时检查,这正是buildGold所提供的;显然,永远不会有一个程序能够保证人类不会输入一些不需要的东西。
在对你的问题的评论中给出的替代方案也值得考虑。如果您只需要一个函数,myfun,它就会失败,那么就只有myfun :: (Integer, Integer) -> Maybe ???了,那么ADT就有点重了。
发布于 2010-07-10 20:35:42
最简单的技术是使用智能构造器,它使用从Int到GoldenInt的函数,检查您的值是否处于所需的比率。
通过更多的努力,您可以使用类型级数来确保不需要运行时检查,但是,考虑到您是初学者,我将坚持使用智能构造函数方法。
汤姆上面的回答就是这个成语的一个例子。
发布于 2010-07-10 18:20:52
实际上,你能做的最好就是一次运行时检查。可能有一些类型级别的微积分,我不知道(见luqui的评论),但这在Haskell中是不实用的。
你可以使用断言,这就是你想要替换的东西,
checker :: a -> b -> Bool
checker x y = x * 1.618 `approxEqual` y
unsafeMyfun :: a -> b -> c
unsafeMyfun x y = assert (checker x y) (doRealThingWith a b)或返回Maybe a (或Either err a)以避免无法在纯函数中捕获的异常,
myfun :: a -> b -> Maybe c
myfun x y = do
guard $ checker x y
return $ doRealThingWith x y或者使用自定义的契约类型,如Tom的答案等。无论如何,在编译时不可能检查约束(编译时)。事实上,由于In,任何编译时约束都不能精确。
https://stackoverflow.com/questions/3220246
复制相似问题