点(.)和美元符号有($)什么区别?据我了解,它们都是不需要使用括号的语法糖.
我一直在阅读真实世界的哈斯克尔,我即将结束,但风格问题一直在与我(.)和($)操作员徘徊.
当你编写一个由其他函数组成的函数时,你可以这样写:
f = g . h
Run Code Online (Sandbox Code Playgroud)
但是当你在这些函数的末尾应用某些东西时,我会这样写:
k = a $ b $ c $ value
Run Code Online (Sandbox Code Playgroud)
但是这本书会像这样写:
k = a . b . c $ value
Run Code Online (Sandbox Code Playgroud)
现在,对我来说,他们看起来功能相同,他们在我眼中完全一样.然而,我看的越多,我就越看到人们以书的方式编写他们的函数:(.)首先构成,然后仅在最后使用($)附加值来评估该批次(没有人用很多美元组成) .
是否有理由使用比使用所有($)符号更好的书籍方式?或者这里有一些我没有得到的最佳实践?或者它是多余的,我根本不应该担心它?
我试图理解点运算符在这个Haskell代码中做了什么:
sumEuler = sum . (map euler) . mkList
Run Code Online (Sandbox Code Playgroud)
整个源代码如下.
点运算符将两个函数sum以及结果map euler和结果mkList作为输入.
但是,sum它不是函数,它是函数的参数,对吧?那么这里发生了什么?
还有,(map euler)做什么?
mkList :: Int -> [Int]
mkList n = [1..n-1]
euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))
sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList
Run Code Online (Sandbox Code Playgroud) 为什么这个类型检查:
runST $ return $ True
Run Code Online (Sandbox Code Playgroud)
虽然以下不是:
runST . return $ True
Run Code Online (Sandbox Code Playgroud)
GHCI抱怨:
Couldn't match expected type `forall s. ST s c0'
with actual type `m0 a0'
Expected type: a0 -> forall s. ST s c0
Actual type: a0 -> m0 a0
In the second argument of `(.)', namely `return'
In the expression: runST . return
Run Code Online (Sandbox Code Playgroud) 我已经看到很多函数是根据模式定义的(f .) . g.例如:
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
Run Code Online (Sandbox Code Playgroud)
这是什么意思?
haskell functional-programming pointfree function-composition tacit-programming
我试图了解结果
(*) . (+)
Run Code Online (Sandbox Code Playgroud)
在哈斯克尔.我知道合成算子只是数学函数的标准组成 - 所以
(f . g) = f (g x)
Run Code Online (Sandbox Code Playgroud)
但:
(*) . (+) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
Run Code Online (Sandbox Code Playgroud)
我很难理解这种类型的签名.我希望能够做到这样的事情:
((*) . (+)) 1 2 :: Num a => a -> a
= (* (+ 1 2))
Run Code Online (Sandbox Code Playgroud)
的意义是什么 (*) .(+)的签名?我尝试用它来玩它(只是匹配它的签名):
((*) . (+)) 1 (\x -> x + 1) 1
Run Code Online (Sandbox Code Playgroud)
但那无法编译.我正在尝试在编写这些步骤时完成逻辑步骤,但我还没有完全理解它是如何得到这个结果的(以及结果是什么).
普通的功能组成属于这种类型
(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)
我认为这应该概括为类型:
(.) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
Run Code Online (Sandbox Code Playgroud)
一个具体的例子:计算差分平方.我们可以写diffsq a b = (a - b) ^ 2,但感觉我应该能够编写(-)和(^2)编写类似的东西diffsq = (^2) . (-).
当然,我不能.我可以做的一件事是使用一个元组而不是两个参数(-),通过转换它uncurry,但这不一样.
有可能做我想要的吗?如果没有,我误解的是什么让我认为它应该是可能的?
注意:这里已经有效地提出过这个问题,但是没有给出答案(我怀疑必须存在).
如果我想申请f第一和g第二,我必须写:
g . f
Run Code Online (Sandbox Code Playgroud)
是否有另一种标准语法允许我以相反的顺序编写函数?
f <whatever> g
Run Code Online (Sandbox Code Playgroud)
我知道我可以发明自己的语法:
compose f g x = g (f x)
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
f `compose` g
Run Code Online (Sandbox Code Playgroud)
但我宁愿使用标准的库设施.
好吧,所以我不是Haskell程序员,但我对Haskell背后的许多想法非常感兴趣,并且我正在研究它.但是我被困在第一个方面:我似乎无法绕过Monads,这似乎是相当基础的.我知道有一百万个关于SO的问题要求解释Monads,所以我会更加具体地说明了什么在困扰我:
我读了这篇优秀的文章(Javascript中的介绍),并认为我完全了解Monads.然后我读了Monads上的维基百科条目,看到了:
多态类型(M t)→(t→M u)→(M u)的绑定操作,其中Haskell由中缀运算符表示>> =.它的第一个参数是monadic类型的值,它的第二个参数是一个函数,它从第一个参数的基础类型映射到另一个monadic类型,其结果是在其他monadic类型中.
好的,在我引用的文章中,bind是一个仅占用一个参数的函数.维基百科说两个.我认为我对Monads的理解如下:
但是肯定有一些错误,因为我的bind概念需要一个参数:一个函数.但是(根据维基百科)Haskell的绑定实际上有两个参数!我的错误在哪里?
数学上,函数组合操作是关联的.因此:
f . (g . h) = (f . g) . h
Run Code Online (Sandbox Code Playgroud)
因此,功能组合操作可以被定义为左关联或右关联.
由于Haskell中的正常函数应用(即术语的并置,而不是$操作)在我看来是左联想的,因此函数组合也应该是左联的.毕竟世界上大多数人(包括我自己)习惯于从左到右阅读.
然而,Haskell中的函数组合是正确的关联:
infixr 9 .
Run Code Online (Sandbox Code Playgroud)
我知道函数组合操作是左关联还是右关联并没有什么区别.尽管如此,我很想知道它为什么不留下联想.我想到这个设计决定有两个原因:
$操作类似.除了笑话,在Haskell中,函数组合是否存在正确联想是否有任何有益的理由?如果Haskell中的函数组合是左对联的,它会有什么不同吗?