Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.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
Function 函数的类型类实例_Function_Haskell_Monads_Functor_Applicative - Fatal编程技术网

Function 函数的类型类实例

Function 函数的类型类实例,function,haskell,monads,functor,applicative,Function,Haskell,Monads,Functor,Applicative,我刚刚意识到,函数有Monad、Functor和Applicative的实例 当我看到一些我没有得到的typeclass实例时,我通常会编写一些类型良好的表达式,看看它返回什么: 有人能解释一下这些例子吗?你通常会听说List和Maybe的实例,这对我来说很自然,但我不明白函数怎么可能是函子,甚至是单子 编辑: 好的,这是一个有效的类型良好的表达式,它不会编译: fmap (+) (+) 1 (+1) 1 首先,我同意你的观点:函数不像函子那样直观,事实上,我有时希望这些实例不存在。这并不是说

我刚刚意识到,函数有Monad、Functor和Applicative的实例


当我看到一些我没有得到的typeclass实例时,我通常会编写一些类型良好的表达式,看看它返回什么:

有人能解释一下这些例子吗?你通常会听说List和Maybe的实例,这对我来说很自然,但我不明白函数怎么可能是函子,甚至是单子

编辑: 好的,这是一个有效的类型良好的表达式,它不会编译:

fmap (+) (+) 1 (+1) 1

首先,我同意你的观点:函数不像函子那样直观,事实上,我有时希望这些实例不存在。这并不是说它们有时没有用处,而是它们经常被用在一种不必要和令人困惑的方式中。这些方法总是可以用更具体的组合词(特别是来自
Control.Arrow
的组合词)或等效但更具描述性的组合词替换

也就是说。。。为了理解函数函子,我建议您先考虑一下。在某种程度上,
Map Int
非常类似于数组:它包含一些可以转换的元素(即
fmap
over),您可以通过使用整数索引来访问单个元素
Map
只允许“数组”中有间隙,并将整数索引推广到可以排序的任何类型的索引

但在另一个视图中,
Map
只是函数的一个特定实现:它将参数(键)与结果(值)关联起来。这应该很清楚函数函子是如何工作的:它覆盖函数的所有可能结果†

不幸的是,这种解释并不能很好地解释
Monad
实例,因为
Map
实际上没有Monad(甚至
Applicative
)实例。列表/数组实现的直接自适应实际上是不可能的。。。在名单上,我们有

pure x ≡ [x]
(,) <$> [a,b] <*> [x,y,z] ≡ [(a,x),(a,y),(a,z),(b,x),(b,y),(b,z)]
请注意,元素的索引是保留的

现在,只要有一个
repeat::a->mapka
生成器,这个实例实际上就可以适用于
Map
。这是不存在的,因为通常有无限多个键,我们无法全部枚举它们,也无法平衡这样一个
映射所需要的无限树。但是如果我们将自己限制为只有有限多个可能值的键类型(例如
Bool
),那么我们就很好:

instance Applicative (Map Bool) where
  pure x = Map.fromList [(False, x), (True, x)]
  <*> = Map.intersectWith ($)
实例应用程序(Map Bool)其中
纯x=Map.fromList[(False,x),(True,x)]
=Map.intersectWith($)
现在,这正是函数monad的工作方式,与
Map
不同的是,如果可能有无限多个不同的参数,则没有问题,因为您从未尝试将所有参数与相关值一起存储;相反,您总是只在现场计算值



†如果不是懒洋洋地完成,这将是不可行的——在哈斯克尔,这几乎不是问题,事实上,如果你在
地图上fmap,它也会懒洋洋地发生。对于函数functor,
fmap
实际上不仅是惰性的,而且结果也会立即被遗忘,需要重新计算。

fmap
For functions作用于函数生成的结果:

GHCi> :set -XTypeApplications
GHCi> :t fmap @((->) _)
fmap @((->) _) :: (a -> b) -> (t -> a) -> t -> b
GHCi> :t join @((->) _)
join @((->) _) :: (t -> t -> a) -> t -> a
GHCi> join (*) 5
25
通过
a->b
函数修改
t->a
函数的
a
结果。如果这听起来很像函数合成,那是因为它确实是:

GHCi> fmap (3 *) (1 +) 4
15
GHCi> ((3 *) <$> (1 +)) 4
15
GHCi> ((3 *) . (1 +)) 4
15
下面是一个以应用程序风格编写的示例,使用函数的
Functor
applicative
实例:

GHCi> ((&&) <$> (> 0) <*> (< 4)) 2
True
。。。用
a
而不是其他任何东西生成
t->a
函数。常量函数是实现此目的的唯一方法:

GHCi> pure 2 "foo"
2
GHCi> pure 2 42
2
请注意,
pure 2
在上述每个示例中都有不同的类型

考虑到以上所有因素,
Monad
实例令人惊讶地乏味。为了更清楚,让我们看一下
(==)


那是你的密码吗?第一个问题是有一个解析错误:括号不匹配。是的,我修复了该代码片段中的
Functor
实例仅用于列表,因为
fmap
的第二个参数是列表。您实际上是在尝试将
(+1)
作为
+
的第一个参数,即添加一个函数。函数没有标准的
+
重载。为什么你要尝试使用函数的
头呢?“当我看到一些我没有得到的typeclass实例时,我通常做的是编写一些类型良好的表达式,看看它返回什么”——这是一个非常好的方法;只是,在这种情况下,正如其他人所指出的,根本不需要涉及列表,这可能使您的尝试偏离了轨道。您迭代了函数的所有可能输入?@hgiesel语义上是的。在操作上,当然不是;您只需输出一个函数,等待用户查询特定输入,然后修改该特定输入的输出。使用具有启发性的“数组”类比作为命名建议:
fmap f arrayLikeFunction=\userRequest->f(arrayLikeFunction userRequest)
;或者使用
Map
类比:
fmap f mapLikeFunction=\key->f(mapLikeFunction键)
GHCi> ((&&) <$> (> 0) <*> (< 4)) 2
True
GHCi> :t pure @((->) _)
pure @((->) _) :: a -> t -> a
GHCi> pure 2 "foo"
2
GHCi> pure 2 42
2
GHCi> :t (=<<) @((->) _)
(=<<) @((->) _) :: (a -> t -> b) -> (t -> a) -> t -> b
GHCi> :t join @((->) _)
join @((->) _) :: (t -> t -> a) -> t -> a
GHCi> join (*) 5
25