Haskell无点式编程 [英] Haskell pointfree programming

查看:96
本文介绍了Haskell无点式编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



1我试图了解Haskell中的pointfree编程,以及我对某些示例的疑问,因为我不太了解发生错误时给出的解释。 )我有一个循环函数定义如下:

  myCycle :: [a]  - > [a] 
myCycle = foldr(++)[]。重复

为什么 myCycle = foldr(++)[] $ repeat 不工作?



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

  sum :: [Int]  - > [Int]  - > [Int] 
sum s = zipWith(+)。 map(+ 2)$ s

为什么函数与 sum s = zipWith(+)$ map(+ 2)s 为什么 sum l1 l2 = zipWith(+)。 map(+ 2)$ l1 $ l2 不工作

解决方案

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

  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]

现在,您可以看到($)根本不会改变类型。它的固定性确保你可以使用它而不是括号。让我们来看看它们的区别:

 ($)(foldr(++)[]):: [[a]]  - > [a] 
(。)(foldr(++)[])::(b - > [[a]]) - > b - >由于 repeat 的类型为



c - > [c] ,它不适用于($)。它确实与(。)有关,因为 c〜[a] 可以正常工作。



因此,请始终记住,($)本身不会做任何事情。它仅仅改变了优先性/固定性。另外,如果您尝试理解/出现无点代码,则可以使用前缀符号而不是中缀:

  sum l1 (+)(map(+2)l1)$ l2 = zipWith(+)(map(+2)l1) +2)l1))l2 
- 摆脱($)和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 - 再次替换f和g
= zipWith(+)。(map(+2)$ l1
- 摆脱$和l1:
sum = zipWith(+)。map(+2)


I am trying to understand pointfree programming in Haskell and I questions on some examples, because I don't really understand the explanation given when the errors occur.

1) I have a cycle function defined below:

myCycle :: [a] -> [a]
myCycle = foldr (++) [] . repeat

Why does myCycle = foldr (++) [] $ repeat not work?

2) Add every element of a list with 2 then add with another list

sum :: [Int] -> [Int] -> [Int]
sum s = zipWith (+) . map (+ 2) $ s

Why does the function has the same result with sum s = zipWith (+) $ map (+ 2) s and why does sum l1 l2 = zipWith (+) . map (+ 2) $ l1 $ l2 not work

解决方案

First of all, let's list all types:

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]

Now, as you can see, ($) doesn't change the type at all. It's just so that its fixity makes sure that you can use it instead of parentheses. Let's see how they differ:

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

Since repeat has type c -> [c], it doesn't work with ($). It sure does with (.), since c ~ [a] works fine.

So always keep in mind that ($) doesn't do anything on its own. It merely changes the precedence/fixity. Also, it sometimes helps if you use prefix notation instead of infix if you try to understand/come to pointfree code:

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)

这篇关于Haskell无点式编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆