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

Function 制作以Float或Double作为输入的函数的最好方法是什么?,function,haskell,floating-point,Function,Haskell,Floating Point,假设我想实现费米函数(逻辑曲线的最简单示例),这样,如果通过Float它将返回Float,如果通过Double它将返回Double。以下是我得到的: e = 2.7182845904523536 fermiFunc :: (Floating a) => a -> a fermiFunc x = let one = fromIntegral 1 in one/(one + e^(-x)) 问题是ghc说e是Double。定义变量one也有点恶心。我想到的另一个解决方案是只定义dou

假设我想实现费米函数(逻辑曲线的最简单示例),这样,如果通过
Float
它将返回
Float
,如果通过
Double
它将返回
Double
。以下是我得到的:

e = 2.7182845904523536

fermiFunc :: (Floating a) => a -> a
fermiFunc x = let one = fromIntegral 1 in one/(one + e^(-x))
问题是ghc说
e
Double
。定义变量
one
也有点恶心。我想到的另一个解决方案是只定义double的函数:

e = 2.7182845904523536

fermiFuncDouble :: Double -> Double
fermiFuncDouble x = 1.0/(1.0 + e^(-x))
然后使用

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

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

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

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

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

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

一般来说,“如何编写一个能处理多种类型的函数?”的答案是“编写它,使它能普遍适用于所有类型。”(参数多态性,如
map
),“查找(或创建)它们共享的一个或多个类型类,以提供所需的行为。”(特殊多态性,如
show
),或者“创建一个新类型,该类型是这些类型的总和。”(如

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


您可以在GHCi中使用
:i
列出实例和实例方法,这可能会帮助您找到合适的typeclass。

永远不要用任何语言编写
e^x
。这不是指数函数,而是幂函数


指数函数被称为
exp
,它的定义实际上与幂运算几乎没有关系–它被定义为泰勒级数或常微分方程d⁄染料,但
e**(-x)
转换为
exp(-x)*log e)
,其中
loge
是一种非常低效的写入
1
的方法。(虽然没有定义
one=from integral 1
,效率那么低,当然……)这是真的,我很高兴你的答案纠正了这一点,但我认为我的其余答案仍然有用。误用
e
与这个问题有些不相干,这实际上是关于特殊多态性的问题,依我看。
fermiFunc=recip。成功。经验。尽管否定
很漂亮。最小的变化是给
e
一个多态类型签名,就像你给
fermiFunc
做的那样。根本不需要定义一个
;只需使用
1
即可。但这里的答案表明,更激进的变革是伟大的。
> :t fermiFunc
fermiFunc :: (Floating a) => a -> a