制作一个以Float或Double作为输入的函数的最好方法是什么?

时间:2017-08-14 19:03:13

标签: function haskell floating-point

假设我想实现Fermi函数(逻辑曲线的最简单示例),这样如果它传递了Float,它将返回Float,如果它是通过Double,它返回Double。这就是我所拥有的:

e = 2.7182845904523536

fermiFunc :: (Floating a) => a -> a
fermiFunc x = let one = fromIntegral 1 in one/(one + e^(-x))

问题是ghc说eDouble。定义变量one也有点粗糙。我想到的另一个解决方案就是定义双打函数:

e = 2.7182845904523536

fermiFuncDouble :: Double -> Double
fermiFuncDouble x = 1.0/(1.0 + e^(-x))

然后使用Either

fermiFunc :: (Floating a) => Either Float Double -> a
fermiFunc Right x = double2Float (fermiFuncDouble (float2Double x))
fermiFunc Left x = fermiFuncDouble x

这并不令人兴奋,因为我可能刚刚为Float案例编写了一个单独的函数来处理转换并调用fermiFuncDouble。有没有一种很好的方法来为这两种类型编写函数?

2 个答案:

答案 0 :(得分:8)

假设您想要浮点指数,那就是(**)(^)是积分指数。重写你的函数以使用(**)并让GHC推断出类型给出:

fermiFunc x = 1/(1 + e ** (-x))

> :t fermiFunc
fermiFunc :: (Floating a) => a -> a

由于FloatDouble都有Floating个实例,fermiFunc现在具有足够的多态性,可以同时使用这两个实例。

(注意:您可能需要声明e的多态类型以绕过单态限制,即e :: Floating a => a。)

一般来说,答案是"如何编写适用于多种类型的函数?"是"写它以便它适用于所有类型。" (参数多态,如map),"查找(或创建)他们共享的一个或多个类型,提供您需要的行为。" (ad hoc多态,如show),或"创建一个新类型,即这些类型的总和。" (如Either)。

后两者有一些权衡。例如,类型类是打开的(您可以随时添加更多),而总和类型是关闭的(您必须修改定义以添加更多类型)。求和类型要求您知道要处理的类型(因为它必须与构造函数匹配),而类型类允许您编写多态函数。

您可以在GHCi中使用:i列出实例并列出实例方法,这可能有助于您找到合适的类型类。

答案 1 :(得分:8)

不要用任何语言写global $post; 。这不是指数函数,而是幂函数

指数函数被称为e^x,其定义实际上与动力操作无关 - 它根据您的喜好定义为泰勒级数或the unique solution至普通微分方程 d / d exp = exp,边界条件exp 0 = 1.现在,对于任何理性 n ,我们都会发生这种情况exp n ≡(exp 1) n 这也激励着为ℚ或ℂ中的数字定义幂运算,即为< / p>

a z := exp( z ·ln a )< / p>

...但 e 应该被理解为只是编写exp()本身的快捷方式。

因此,不应在某处定义exp并尝试利用它的某些功能,而应该使用exp

e

......或者确实

fermiFunc :: Floating a => a -> a
fermiFunc x = 1/(1 + exp (-x))