嗨伙计们,有人可以解释我作为一个haskell noob运营商:
(.) :: (b -> c) -> (a -> b) -> a -> c
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
做什么?当我看到签名时,我什么都不知道,只需要一些简单易懂的解释就可以帮助我。
答案 0 :(得分:14)
我也在学习Haskell,我的建议是查看Learn You a Haskell for Great Good!,更准确地说:
(.)
阅读Function composition <$>
和<*>
阅读Applicative functors 本质上:
(.)
是功能组合:如果您有g :: a -> b
和f :: b -> c
,那么f . g
基本上是f(g(x))
:首先使用g
在a
上获取b
,然后在f
上使用b
获取c
<$>
接受a
并返回b
的函数,以及包含 a
的仿函数,以及它返回一个包含 b
的仿函数。因此<$>
与fmap :: (a -> b) -> f a -> f b
<*>
带有一个包含的函数,该函数带有a
并返回b
,以及包含<的仿函数/ em> a
,它会返回包含 a b
的仿函数。所以<*>
种提取来自仿函数的函数并将其应用于仿函数内的参数,最后将结果返回到仿函数中
注意您在书籍章节中找到的解释比我上面的尝试更好
答案 1 :(得分:5)
也许你通过例子学习(就像我一样),所以这里有一些你可以在GHCI中搞砸的简单。
(.) - Function Composition
-- (.) :: (b -> c) -> (a -> b) -> a -> c
> f = (+1)
> g = (*2)
> a = f . g
> a 0
1 -- f( g( 0 ) ) or (0 * 2) + 1
> b = g . f
> b 0
2 -- g( f( 0 ) ) or (0 + 1) * 2
<$> - Functor
-- (<$>) :: Functor f => (a -> b) -> f a -> f b
> a = (*2)
> b = Just 4
> a <$> b
Just 8
<*> - Applicative
-- (<*>) :: Applicative f => f (a -> b) -> f a -> f b
> a = Just (*2)
> b = Just 4
> a <*> b
Just 8
我希望有所帮助。
答案 2 :(得分:3)
(.)
运算符组成函数。例如,\x -> f (g x)
与f . g
相同。您可以为任意功能执行此操作,例如\x -> f (g (h x))
等于f . g . h
。
<$>
和<*>
运算符未在功能方面定义。它们的功能取决于它们应用的实际类型f
。 <$>
运算符是fmap
库中Functor
函数的替代运算符。例如,对于Maybe
类型,它采用左操作数,并且仅在右操作数为Just
值时才应用它。因此,为了找出这些运算符的作用,请查看特定类型的实现。
答案 3 :(得分:1)
虽然<$>
和<*>
的常见用法因为它们在类型类中而变得模糊,但您通常可以阅读该信息的haddock文档。如果您很难找到函数所属的模块,请使用Hoogle。
答案 4 :(得分:0)
我是Haskell的新手,有时Haskell类型的声明也让我感到困惑。
一开始很容易迷失,因为教程说Capitalization
命名约定通常用于类型声明,而camelCase
命名约定通常用于变量。
实际上,这属于Haskell中的一种更高级的技术,可能是多态性。只需将f
,a
和b
视为某些类型变量 - 处理类型的变量。 Haskell中的class
不是像OOP那样的对象,而是type
。因此Functor f
表示类型f
属于class Functor
,依此类推。
如果您将这些字母a
,b
,c
替换为某种类型 - 名为 instance
- 例如String
Int
Char
。这将是有道理的:
(.) :: (Int -> Char) -> (String -> Int) -> String -> Char
(<$>) :: Functor Maybe => (String -> Int) -> Maybe String -> Maybe Int -- type `Maybe` belongs to class `Functor`
...