Haskell无点编程

zai*_*aig 0 haskell

我试图理解Haskell中的无点编程,并且我对一些例子提出了疑问,因为我并不真正理解错误发生时给出的解释.

1)我有一个循环函数定义如下:

myCycle :: [a] -> [a]
myCycle = foldr (++) [] . repeat
Run Code Online (Sandbox Code Playgroud)

为什么不起作用myCycle = foldr (++) [] $ repeat

2)用2添加列表的每个元素,然后添加另一个列表

sum :: [Int] -> [Int] -> [Int]
sum s = zipWith (+) . map (+ 2) $ s
Run Code Online (Sandbox Code Playgroud)

为什么函数有同样的结果sum s = zipWith (+) $ map (+ 2) s?为什么sum l1 l2 = zipWith (+) . map (+ 2) $ l1 $ l2不工作

Zet*_*eta 6

首先,让我们列出所有类型:

foldr  :: (a -> b -> b) -> b -> [a] -> b
(++)   :: [a] -> [a] -> [a]
[]     :: [a]
repeat ::  a  -> [a]
(.)    :: (b -> c) -> (a -> b) -> a -> c
($)    :: (a -> b) -> a -> b

foldr (++)          :: [a] -> [[a]] -> [a]
foldr (++) []       ::        [[a]] -> [a]
Run Code Online (Sandbox Code Playgroud)

现在,正如您所看到的,($)根本不会改变类型.它的固定性确保您可以使用它而不是括号.让我们看看他们有何不同:

($) (foldr (++) []) :: [[a]]             -> [a]
(.) (foldr (++) []) :: (b -> [[a]]) -> b -> [a]
Run Code Online (Sandbox Code Playgroud)

由于repeat有类型c -> [c],它不起作用($).确实如此(.),因为c ~ [a]工作正常.

因此,请始终牢记,($)它本身不会做任何事情.它只是改变了优先级/固定性.此外,如果您尝试理解/来到无点代码,如果您使用前缀表示法而不是中缀,它有时会有所帮助:

sum l1 l2 = zipWith (+) (map (+2) l1) l2
          = zipWith (+) (map (+2) l1) $ l2
          = ($) (zipWith (+) (map (+2) l1)) l2
-- get rid  of both ($) and l2:
sum l1    = zipWith (+) (map (+2) l1)
          = (zipWith (+)) ((map (+2)) l1)
          = f (g l1)                           -- f = zipWith (+), g = map (+2) 
          = (f . g) l1
          = (zipWith (+) . (map (+2)) l1       -- substitute f and g again
          = zipWith (+) . (map (+2) $ l1
-- get rid of $ and l1:
sum       = zipWith (+) . map (+2)
Run Code Online (Sandbox Code Playgroud)