Rab*_*ski 682 syntax haskell function-composition
点(.)
和美元符号有($)
什么区别?据我了解,它们都是不需要使用括号的语法糖.
Mic*_*ele 1190
该$
操作是为了避免括号.在它之后出现的任何东西都将优先于之前的任何东西.
例如,假设您有一行内容如下:
putStrLn (show (1 + 1))
Run Code Online (Sandbox Code Playgroud)
如果你想摆脱这些括号,以下任何一行也会做同样的事情:
putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1
Run Code Online (Sandbox Code Playgroud)
.
运算符的主要目的不是避免括号,而是链函数.它允许您将右侧显示的内容的输出与左侧显示的输入相关联.这通常也会导致括号减少,但工作方式也不同.
回到同一个例子:
putStrLn (show (1 + 1))
Run Code Online (Sandbox Code Playgroud)
(1 + 1)
没有输入,因此不能与.
操作员一起使用.show
可以拿一个Int
并返回一个String
.putStrLn
可以拿一个String
并返回一个IO ()
.你可以链接show
到putStrLn
这样:
(putStrLn . show) (1 + 1)
Run Code Online (Sandbox Code Playgroud)
如果您喜欢这个括号太多,请与$
运营商一起摆脱它们:
putStrLn . show $ 1 + 1
Run Code Online (Sandbox Code Playgroud)
GS *_*ica 180
它们有不同的类型和不同的定义:
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x
Run Code Online (Sandbox Code Playgroud)
($)
旨在取代正常的功能应用程序,但在不同的优先级,以帮助避免括号.(.)
用于组合两个函数以创建新函数.
在某些情况下,它们是可以互换的,但总的来说并非如此.它们的典型示例是:
f $ g $ h $ x
Run Code Online (Sandbox Code Playgroud)
==>
f . g . h $ x
Run Code Online (Sandbox Code Playgroud)
换句话说,在一连串的$
s中,除最后一个之外的所有部分都可以被替换.
Mar*_*ijn 122
另请注意,这($)
是专用于函数类型的标识函数.标识函数如下所示:
id :: a -> a
id x = x
Run Code Online (Sandbox Code Playgroud)
虽然($)
看起来是这样的:
($) :: (a -> b) -> (a -> b)
($) = id
Run Code Online (Sandbox Code Playgroud)
请注意,我有意在类型签名中添加了额外的括号.
使用的($)
,通常可以通过添加括号(除非操作者在一个部分中使用)来消除.例如:f $ g x
成为f (g x)
.
使用(.)
通常稍微难以更换; 它们通常需要lambda或引入显式函数参数.例如:
f = g . h
Run Code Online (Sandbox Code Playgroud)
变
f x = (g . h) x
Run Code Online (Sandbox Code Playgroud)
变
f x = g (h x)
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
小智 77
($)
允许将函数链接在一起而不添加括号来控制评估顺序:
Prelude> head (tail "asdf")
's'
Prelude> head $ tail "asdf"
's'
Run Code Online (Sandbox Code Playgroud)
compose运算符(.)
在不指定参数的情况下创建新函数:
Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'
Prelude> let second = head . tail
Prelude> second "asdf"
's'
Run Code Online (Sandbox Code Playgroud)
上面的例子可以说是说明性的,但并没有真正显示使用组合的便利性.这是另一个类比:
Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"
Run Code Online (Sandbox Code Playgroud)
如果我们只使用第三次,我们可以避免使用lambda来命名它:
Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"
Run Code Online (Sandbox Code Playgroud)
最后,组合让我们避免lambda:
Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"
Run Code Online (Sandbox Code Playgroud)
Chr*_*oph 29
一个有用的应用程序,花了我一些时间从非常简短的描述中弄清楚了解一个haskell:自:
f $ x = f x
Run Code Online (Sandbox Code Playgroud)
并且将包含中缀运算符的表达式的右侧括起来将其转换为前缀函数,可以编写($ 3) (4+)
类似的函数(++", world") "hello"
.
为什么有人会这样做?例如,对于函数列表.都:
map (++", world") ["hello","goodbye"]`
Run Code Online (Sandbox Code Playgroud)
和:
map ($ 3) [(4+),(3*)]
Run Code Online (Sandbox Code Playgroud)
比更短的map (\x -> x ++ ", world") ...
或map (\f -> f 3) ...
.显然,后者的变体对大多数人来说更具可读性.
Aar*_*all 13
Haskell:(
.
点)和$
(美元符号)之间的差异点
(.)
和美元符号有($)
什么区别?据我了解,它们都是不需要使用括号的语法糖.
他们是不是语法糖不需要使用括号-它们是功能- infixed,因此,我们可以称他们为运营商.
(.)
以及何时使用它.(.)
是撰写功能.所以
result = (f . g) x
Run Code Online (Sandbox Code Playgroud)
是相同的构建通过参数传递到的结果的功能g
上f
.
h = \x -> f (g x)
result = h x
Run Code Online (Sandbox Code Playgroud)
使用(.)
时,你没有可用的传递给你希望组成函数的参数.
($)
以及何时使用它($)
是具有低绑定优先级的右关联应用函数.所以它只是首先计算它右边的东西.从而,
result = f $ g x
Run Code Online (Sandbox Code Playgroud)
在程序上是相同的(这很重要,因为Haskell被懒惰地评估,它将首先开始评估f
):
h = f
g_x = g x
result = h g_x
Run Code Online (Sandbox Code Playgroud)
或者更简洁:
result = f (g x)
Run Code Online (Sandbox Code Playgroud)
($)
在将前面的函数应用于结果之前,要使用所有要评估的变量时使用.
我们可以通过阅读每个函数的源来看到这一点.
这里的来源为(.)
:
-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)
Run Code Online (Sandbox Code Playgroud)
而这里的来源为($)
:
-- | Application operator. This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- > f $ g $ h x = f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
Run Code Online (Sandbox Code Playgroud)
在不需要立即评估函数时使用合成.也许你想将由合成产生的函数传递给另一个函数.
在提供完整评估的所有参数时使用应用程序.
因此,对于我们的示例,它在语义上更可取
f $ g x
Run Code Online (Sandbox Code Playgroud)
当我们x
(或更确切地说,是g
'的论点)时,做:
f . g
Run Code Online (Sandbox Code Playgroud)
当我们没有.
use*_*780 12
...或者您可以通过使用流水线来避免.
和$
构造:
third xs = xs |> tail |> tail |> head
Run Code Online (Sandbox Code Playgroud)
在您添加辅助函数之后:
(|>) x y = y x
Run Code Online (Sandbox Code Playgroud)
hal*_*csy 11
我的规则很简单(我也是初学者):
.
如果你想传递参数(调用函数),请不要使用,和$
如果还没有参数,请不要使用(撰写函数)那是
show $ head [1, 2]
Run Code Online (Sandbox Code Playgroud)
但从不:
show . head [1, 2]
Run Code Online (Sandbox Code Playgroud)
lol*_*lol 11
了解任何事物(任何功能)的好方法是记住一切都是功能!一般的口头禅有所帮助,但在特定情况下,如操作员,它有助于记住这个小技巧:
:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)
和
:t ($)
($) :: (a -> b) -> a -> b
Run Code Online (Sandbox Code Playgroud)
只需记住:t
自由使用,并将操作员包裹起来()
!
归档时间: |
|
查看次数: |
154381 次 |
最近记录: |