我对haskell很新,对它的类型系统还不太满意.我想知道,如果有能力定义类型(数据类型?),哪些实例可以作为函数调用?
类似物是
__call__
Run Code Online (Sandbox Code Playgroud)
Python中的方法或类方法
operator()
Run Code Online (Sandbox Code Playgroud)
在c ++中.(更多示例在维基百科中给出"功能对象"一词).
应用这种结构的例子是Polynom.该对象由其系数列表定义,即我希望有这样的类型:
data Num a => Polynom a = Polynom [a]
deriving (...)
Run Code Online (Sandbox Code Playgroud)
现在我当然可以定义功能
callPoly :: Num a => (Polynom a) -> a -> a
callPoly p x = ... -- implementation: extract coefficients of p,
-- construct polynomial and call it on x
Run Code Online (Sandbox Code Playgroud)
(这里我不打扰,能够在Floats上用Int系数调用多项式......这只是技术细节)
现在我可以在我的polinomial上调用它(在交互式提示符中):
let myPoly = Polynomial [1 2 3]
let applicationResult = callPoly myPoly 3
Run Code Online (Sandbox Code Playgroud)
但这种方式并不太花哨.希望能够直接调用多项式作为
let applicationResult = myPoly 3
Run Code Online (Sandbox Code Playgroud)
所以问题是:可以定义这样的多项式类型,可以调用哪些对象(实例)(用作函数)?可能是这种模式可能以其他方式实现,不涉及"数据"?可能是一些玩功能类型或smth.其他?
当然,这个想法不仅可以应用于多项式.实际上,对于任何必须"具有类型"并具有"一些附加数据"的函数(在多项式的情况下 - 它是系数).
或者,如果这是不可能的,那么是否有一些特定的原因或者它不被支持?
PS:在我看来,直接方法(如上所述)是不可能的,因为要可调用myPoly必须是类型(Int - > Int).但是类型(Int - > Int)不能附加任何数据(ig多项式系数).但我想确保,我是对的.
熟悉C++"函数对象"概念是很好的,因为这是对Haskell关于使用普通旧函数可以做什么的想法的一个很好的介绍......具体来说,currying,部分应用和传递函数作为其他函数的参数.
在C++中,您的代码看起来像:
class Polynomial {
int coefficients[];
public:
Polynomial(int coefficients[]) { /* ... */ }
int operator() (int value) { /* ... */ }
};
int coefficients[] = {1, 2, 3};
Polynomial(coefficients)(4); // note the syntax here!
Run Code Online (Sandbox Code Playgroud)
这从根本上表达了一个单一的纯函数:一个多项式求值器,它取一系列的系数和一个值.它可以很容易地在C++中表达为:
int evaluatePolynomial(int coefficients[], int value);
int coefficients[] = {1, 2, 3};
evaluatePolynomial(coefficients, 4);
Run Code Online (Sandbox Code Playgroud)
但这种形式不是令行禁止为以前的形式.关于咖喱形式的好处是你可以说:
Polynomial p = Polynomial(coefficients);
p(4);
p(5);
p(6);
Run Code Online (Sandbox Code Playgroud)
代替:
evaluatePolynomial(coefficients, 4);
evaluatePolynomial(coefficients, 5);
evaluatePolynomial(coefficients, 6);
Run Code Online (Sandbox Code Playgroud)
好的.所以我们把这个"函数对象"的东西想象成一个面向对象的编程概念 - 一个伪装成函数的对象 - 但现在让我们忘记对象.如果你在Haskell中看一下它,它只是一个函数,不需要任何用户定义的数据类型来表达:
polynomial :: Num a => [a] -> a -> a
Run Code Online (Sandbox Code Playgroud)
你可以"正常"调用它(evaluatePolynomial()如上所述),立即将它应用于两个参数:
polynomial [1, 2, 3] 4
Run Code Online (Sandbox Code Playgroud)
但由于Haskell函数是curry,你可以部分应用(与Polynomial函数对象一样):
do
let p = polynomial [1, 2, 3]
print (p 4)
print (p 5)
print (p 6)
Run Code Online (Sandbox Code Playgroud)
十分简单.现在,如果你想做一些更接近C++的东西,你有一个代表你的Polynomial函数对象的特定数据类型,你可以这样做......
newtype Polynomial a = P (a -> a) -- function object
mkPolynomial :: Num a => [a] -> Polynomial a -- constructor
Run Code Online (Sandbox Code Playgroud)
......但这种额外的复杂性并没有带来任何好处.你立即注意到没有什么特别的Polynomial,它只是包装一个常规函数,所以你最终只需要再打开它,如:
do
let (P p) = mkPolynomial [1, 2, 3]
print (p 4)
print (p 5)
print (p 6)
Run Code Online (Sandbox Code Playgroud)
简而言之,你在思考问题的过程中,只是在功能而不是对象方面,你的Haskell代码最终会变得更简单,更惯用.
我可能会弄错我的术语,因为我自己也不是 Haskell 的老手。然而,根据我对 Haskell 的理解:
由于 Haskell 不是面向对象的,因此它没有对象或实例(即传统意义上的)。您拥有数据类型的值,而不是数据类型的实例。话虽这么说,由于函数是数据(值),就像整数和字符串一样,因此您可以拥有可调用的值,因为它们可以携带自己的上下文(就像 OO 世界中的实例一样)。
如果您的目标是传递一个带有 的值PolyNom a,您可以简单地部分评估您的函数callPoly,然后将其视为您的“可调用多项式”。例子:
myPoly = PolyNom [1, 2, 3]
callMyPoly = callPoly myPoly
-- or simply
callMyPoly = callPoly (PolyNom [1, 2, 3])
Run Code Online (Sandbox Code Playgroud)
现在,callMyPoly 的类型是:
callMyPoly :: Num a => a -> a
Run Code Online (Sandbox Code Playgroud)
你可以这样称呼它:
callMyPoly 5
Run Code Online (Sandbox Code Playgroud)
这相当于:
callPoly myPoly 5
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
618 次 |
| 最近记录: |