Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中匿名函数的类型_Haskell - Fatal编程技术网

Haskell中匿名函数的类型

Haskell中匿名函数的类型,haskell,Haskell,我在Haskell中键入匿名函数时遇到问题。例如,当我们有: \x -> x 5 在GHCI中检查的类型是numt1=>(t1->t2)->t2,而我确信它是相反的 \x -> a * x isnuma=>a->a(我知道我们需要假设a是一个整数,因为(*)的类型是Int->Int->Int(没有类型类)。 另一个例子是 \f -> f x 据我所知是(a->b)->b 但是我完全关心匿名函数的类型。理解这个函数的魔力是什么?也许可以将这个函数重写为“正常”函数以清楚地看

我在Haskell中键入匿名函数时遇到问题。例如,当我们有:

\x -> x 5
在GHCI中检查的类型是
numt1=>(t1->t2)->t2
,而我确信它是相反的

\x -> a * x
is
numa=>a->a
(我知道我们需要假设a是一个整数,因为(*)的类型是Int->Int->Int(没有类型类)。
另一个例子是

\f -> f x
据我所知是(a->b)->b

但是我完全关心匿名函数的类型。理解这个函数的魔力是什么?也许可以将这个函数重写为“正常”函数以清楚地看到类型


因此,我的问题是:我们如何获得这些类型?它们来自何处以及如何评估这些类型?

以下是编写第一个函数的三种等效方法:

f :: Num t1 => (t1 -> t2) -> t2
f = \x -> x 5

g :: Num t1 => (t1 -> t2) -> t2
g x = x 5

h :: Num t1 => (t1 -> t2) -> t2
h = ($ 5)
请注意,此函数,无论在其定义中使用何种语法,都是二阶函数。这意味着其参数
x
,本身就是一个函数。也就是说,
x
必须具有一种形式
x::constraint1t1,constraint2t2=>t1->t2
。更具体地说,
x
必须接受
5
作为其第一个(可能是唯一的)参数。但这是其参数的唯一固有约束。
5::Num t1=>t1
,因此
x::Num t1,constraint t2=>t1->t2
。对于
x
的返回值没有固有约束,因此最通用(允许的)类型是
x::Num t1=>t1->t2

这给了我们函数参数的类型:
\x->x5::Num t1=>(t1->t2)->?
。但是返回类型呢?好吧,函数只将
x
应用于5,计算结果为(返回值)结果是,您的函数返回与
x
相同的类型。假设您的函数可以接受任何可能的函数
x
,则其类型为
\x->x5::Num t1=>(t1->t2)->t2

还请注意,您可以对参数和类型变量使用任何小写名称。因此,您可以编写
\function->function 5::Num five=>(five->result)->result
>如何获得这些类型

这些类型是Haskell系统可以从它唯一拥有的东西,即用户给出的定义(如“x5”)推断出来的

重要的不是函数是匿名的,而是函数不是显式类型的,因此Haskell系统必须从表达式中“猜测”类型

Prelude> let a=4
Prelude> :t  \x -> a * x
\x -> a * x :: Num a => a -> a
Prelude> 
Prelude> let f1 x = a*x
Prelude> :t f1
f1 :: Num a => a -> a
Prelude> 
因此,匿名版本和命名版本的类型完全相同

当然,您可以更具体地说:

Prelude> let f4 :: Double -> Double ; f4 x = 4*x
Prelude> :t f4
f4 :: Double -> Double
Prelude>
Haskell不会强制您显式键入所有内容。 它将定义和对库函数的调用生成的所有显式类型信息(如f4)和隐式类型信息作为类型约束


如果约束可以被明确地解决,那很好;这就是上面chi提到的类型推断。否则,如果类型约束相互矛盾或不明确,执行就会中止。

我认为您不必以某种方式使它复杂化。基本上当您在Haskell中有一个匿名函数并希望查找类型您需要找到两种类型:首先是
->
符号之前的类型,然后是箭头右侧的整个表达式类型
->
。根据您的示例:

\x -> x 5
我们需要找到x的类型,我们知道这是一个函数,它有一个属于typeclass
Num
类型的参数,并且返回一些未知类型,比如说
t

x :: Num a => a -> t
x 5 :: t
因此
x
函数返回
t
类型的内容:

x :: Num a => a -> t
x 5 :: t
下面是我们的答案:

\x -> x 5 :: Num a => (a -> t) -> t
最后一种情况也是如此:

\f -> f x
f又是一个函数,但这次我们不知道它的参数类型

f :: a -> b
因此
a
x
的类型,右侧的整个表达式返回
b

f x :: b
再一次-在这里,我们有一个表达式类型在
->
的左边和右边

\f -> f x :: (a -> b) -> b

我不明白这里的问题是什么,除了一般的“我不明白类型推断是如何工作的”,太宽泛了。你能说得更具体些吗?@chi-an-issue基本上就是这些例子,它们对它们类型的评估,所以给出的结果将是computed@heisenberg7584您已经给出了类型。在理解为什么这些类型是正确的方面,您有什么具体问题?请编辑您的问题以添加此信息n、 可能重复:。如果不是重复,请说明原因。匿名函数在这里没有什么特别之处。
func x=x 5
与第一个函数完全相同,因此具有相同的类型。您还可以选择限制性更强的类型。例如,您可以定义更专业的函数版本as:
\function->function 5::(浮点->字符串)->String
ok,这很有帮助…但是如果我们有一个表达式,比如;
\x->fxy
。据我所知,这和func x=xy是一样的,对吧?当y甚至不是一个参数时,我们怎么能键入这个呢…@heisenberg7584正确,系统拒绝为\x->fxy指定一个类型,直到你定义了f和y。理论上,mayb它可以这样说(f::t1->t2->t3)=>t1->t3,但不能打扰。我想安全性比抱歉好。很抱歉,只是最后一个。所以当我们有\y->x+y时,类型是
Num a=>a->a
,因为在表达式的左侧只有y,所以我们放了一些常量,例如x=3。所以我们从(+)中删除了一部分类型,因为x在这里是一个常量。如果我们的表达式是\xy->x+y,我们在这里没有常量,因此类型将是
Num a=>a->a->a
,而另一方面
g=x+y
的类型只是Num a=>a