有一天我很无聊,想锻炼我的大脑,所以我决定做99个Haskell问题但是限制自己以无点的方式做这些.当我以无点样式执行操作时,似乎出现了很多问题:如何将多个函数应用于相同的值,同时将每个结果保持为独立实体?使用尖头符号:
foobar x = [id x, reverse x]
Run Code Online (Sandbox Code Playgroud)
到目前为止我用无点符号得出了什么:
foobar' = `map` [id, reverse] ($ x)
Run Code Online (Sandbox Code Playgroud)
我似乎无法x在那里结束.
我编写了以下代码,它使用光泽库获取了一堆点并在屏幕上绘制它们.
let s = blocks pes
pts = map (map mkPt) s {- stitches to points-}
lines = map Line pts {-points to lines -}
pict = Pictures lines {- lines to a picture -}
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)
它工作正常,但我发现有一个重复的模式:一个函数调用链,每个函数调用的结果进入下一个参数的最后一个参数.所以我通过删除中间变量,反转顺序并使用函数组合(".")链接函数来重构,如下所示:
let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)
令人高兴的是,这也很好.但是我想知道我是否会降低可读性,或者我是不是习惯于阅读和编写点免费样式代码.另外,我如何推理这段代码?第二个版本更有效率,还是仅仅更高效?有什么我可以风格化的做法让它更清晰吗?
我在Haskell中有以下功能
agreeLen :: (Eq a) => [a] -> [a] -> Int
agreeLen x y = length $ takeWhile (\(a,b) -> a == b) (zip x y)
Run Code Online (Sandbox Code Playgroud)
我正在努力学习如何编写'惯用'Haskell,它似乎更喜欢使用.而$不是括号,并且在可能的情况下更喜欢无点代码.我似乎无法摆脱提及x和y明确.有任何想法吗?
我认为我对点两个参数的任何函数都有同样的问题.
顺便说一下,这只是为了编写好的代码; 不是一些"使用任何必要的东西来使其无意义"的家庭作业.
谢谢.
(添加评论)感谢您的回答.你已经说服我这个功能不会从pointfree中受益.而且你也给了我一些很好的例子来练习转换表达式.这对我来说仍然很困难,而且它们似乎与Haskell一样重要,因为它指向C.
(.)采用两个函数,它们接受一个值并返回一个值:
(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)
既然(.)有两个参数,我觉得(.).(.)应该是无效的,但它完全没问题:
(.).(.) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?我意识到这个问题措辞严厉......所有的功能都只是因为讨论而采取了一个论点.也许更好的方式来说它是类型不匹配.
可能重复:
Currying减法
我开始了第一个不是来自教程的haskell项目,当然我偶然发现了最简单的东西.
我有以下代码:
moveUp y = modifyMVar_ y $ return . (+1)
moveDn y = modifyMVar_ y $ return . (-1)
Run Code Online (Sandbox Code Playgroud)
我花了一些时间来理解为什么我的代码不能编译:我曾经使用过(-1)这被认为是负面的.将减号括起来并没有帮助,因为它为它添加前缀并使其成为第一个参数.
简而言之,这点的免费版本是什么?
dec :: Num a => a -> a
dec x = x - 1
Run Code Online (Sandbox Code Playgroud) 对于这里的FP认知来说,这看起来真的很明显,但Scala中的点自由风格有什么用呢?在这个主题上真正卖给我的是一个插图,它显示了点自由风格在某些方面(例如性能,优雅,可扩展性,可维护性)如何在非点自由风格中解决相同问题的代码.
我不时偶然发现我想要表达的问题"请使用两次最后一个参数",例如为了编写无点样式或避免使用lambda.例如
sqr x = x * x
Run Code Online (Sandbox Code Playgroud)
可写成
sqr = doubleArgs (*) where
doubleArgs f x = f x x
Run Code Online (Sandbox Code Playgroud)
或者考虑这个稍微复杂的功能(取自这个问题):
ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs)
Run Code Online (Sandbox Code Playgroud)
如果有这样的函数,我可以写这个代码pointfree:
ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where
dup f f1 f2 x = f (f1 x) (f2 x)
Run Code Online (Sandbox Code Playgroud)
但是因为我在Hoogle中找不到像doubleArgs或dup这样的东西,所以我猜我可能会错过这里的伎俩或成语.
根据pointfree:
\x -> (x, x)
Run Code Online (Sandbox Code Playgroud)
相当于:
join (,)
Run Code Online (Sandbox Code Playgroud)
显示这个的推导是什么?
您最有可能写下以下哪项?
r = zip xs $ map sqrt xs
Run Code Online (Sandbox Code Playgroud)
要么
r = [(x, sqrt x) | x <- xs]
Run Code Online (Sandbox Code Playgroud)
互联网上的示例代码似乎表明前者更为丰富且是首选方式.
我有这个代码,我想做点无关;
(\k t -> chr $ a + flip mod 26 (ord k + ord t -2*a))
我怎么做?
除了"想想这个和某些东西"之外,还有一些关于点自由风格的一般规则吗?
pointfree ×10
haskell ×9
coding-style ×3
combinators ×1
currying ×1
refactoring ×1
scala ×1
zip ×1