Haskell 程序程序员的功能代码片段列表?
有时,我仍然无法将过程代码转换为函数代码 是否有映射到过程性习惯用法/代码段的功能性习惯用法/代码段列表 编辑Haskell 程序程序员的功能代码片段列表?,haskell,f#,ocaml,functional-programming,code-snippets,Haskell,F#,Ocaml,Functional Programming,Code Snippets,有时,我仍然无法将过程代码转换为函数代码 是否有映射到过程性习惯用法/代码段的功能性习惯用法/代码段列表 编辑 由于这些代码片段似乎没有一个集中的网站,我将把它变成一个社区wiki。请在这里粘贴任何程序->功能片段。哦,现在这是一个漂亮的问题。以下是一些或一些cloe: for循环可以替换为迭代器 stripped_list=[line.strip()表示行中的行列表] for循环可以替换为apply、map或filter 地图(大写,[“句子”,“片段]) ['句子','片段'] 具有函数
由于这些代码片段似乎没有一个集中的网站,我将把它变成一个社区wiki。请在这里粘贴任何程序->功能片段。哦,现在这是一个漂亮的问题。以下是一些或一些cloe:
- for循环可以替换为迭代器
stripped_list=[line.strip()表示行中的行列表]
- for循环可以替换为apply、map或filter 地图(大写,[“句子”,“片段]) ['句子','片段']
- 具有函数组合的嵌套for循环
- 尾部递归代替循环
- 替代for循环的生成器表达式
sum(x*x表示范围(10)内的x))
; The idea is simple:
; Use parameter passing for binding the values
; of the variables and recursion instead of iteration.
;
; For those who like theory this is the main argument for proving
; that recursive functions (LISP, lambda calculus) have the same
; computational power as any imperative programming language.
(define f-functional (y)
(letrec (
(f-helper (lambda (x y)
(if (p x y)
(f-helper (g x y) y)
(h x y)))))
(f-helper e y)))
; Notice that y in f-helper is invariant. Therefore, we can rewrite
; f-helper without y as follows.
(define f-functional (y)
(letrec (
(f-helper (lambda (x)
(if (p x y)
(f-helper (g x y))
(h x y)))))
(f-helper e)))
; This is not the only solution, though I think it is one of the
; nicer ones.
(自编)
当我第一次在OCaml/F#中访问break/continue时,可以说,它让我陷入了一个(无限)循环,因为不存在这样的东西!在OCaml中,可以使用异常来中断循环,因为它们非常便宜,但在F#(In.NET)中,开销非常高,对于“正常”流控制不有用
这是在不久前使用排序算法时出现的(以消磨时间),该算法大量使用repeat/till和break。我突然想到,递归尾部调用函数可以实现完全相同的结果,而可读性只会略有下降。因此,我抛弃了“可变bDone”和“whilenotBDONE”,并尝试在没有这些命令结构的情况下编写代码。下面只提取循环部分,并展示如何使用tailcalls编写repeat/until、do/while、while/do、break/continue和测试中间样式的代码。所有这些似乎都以与传统F#“while”语句完全相同的速度运行,但您的里程数可能会有所不同(某些平台可能无法正确执行tailcall,因此可能会在修补之前叠加故障)。最后是以两种样式编写的(糟糕的)排序算法,用于比较
让我们从一个“do/while”循环开始,用传统的F-命令式风格,然后看看函数的变化,它既提供了相同类型的循环,也提供了不同的语义,比如while/DO,重复/直到中间测试,甚至中断/继续(没有单元格…嗯,工作流!) 少了单子的休息是怎么回事?好的,只需引入一个返回“unit”的条件表达式,如下所示:
let funBreak() =
let rec loop() =
let x = g()
if x > N then () (*break*)
else
f()
loop()
loop()
继续怎么样?好吧,这只是另一个循环调用!首先,使用语法拐杖:
let funBreakContinue() =
let break' () = ()
let rec continue' () =
let x = g()
if x > N then break'()
elif x % 2 = 0 then
f(); f(); f();
continue'()
else
f()
continue'()
continue'()
let funBreakContinue'() =
let rec loop () =
let x = g()
if x > N then ()
elif x % 2 = 0 then
f(); f(); f();
loop()
else
f()
loop ()
loop()
然后再没有(丑陋的)语法拐杖:
let funBreakContinue() =
let break' () = ()
let rec continue' () =
let x = g()
if x > N then break'()
elif x % 2 = 0 then
f(); f(); f();
continue'()
else
f()
continue'()
continue'()
let funBreakContinue'() =
let rec loop () =
let x = g()
if x > N then ()
elif x % 2 = 0 then
f(); f(); f();
loop()
else
f()
loop ()
loop()
容易极了
这些循环形式的一个很好的结果是,可以更容易地发现和实现循环中的状态。例如,冒泡排序会在整个数组上不断循环,在找到不合适的值时交换这些值。它跟踪通过阵列是否产生任何交换。如果不是,则每个值必须位于正确的位置,以便排序可以终止。作为优化,每次通过数组时,数组中的最后一个值都会被排序到正确的位置。因此,循环可以缩短一次通过。大多数算法检查交换并在每次有交换时更新“bModified”标志。然而,一旦第一次互换完成,就不需要进行该转让;这已经设置为真了
下面是实现冒泡排序的F#代码(是的,冒泡排序是一种糟糕的算法;快速排序)。最后是不改变状态的强制执行;它会为每个exchange更新bModified标志。有趣的是,强制解决方案在小型阵列上速度更快,而在大型阵列上速度仅慢一到两个百分点。(不过,这是一个很好的例子)
let inline sort2 f i j(a:'a数组)=
让i'=a[i]
设j'=a[j]
如果f i'j'>0那么
a、 [i]折叠是一个非常有趣的函数,它是许多函数算法的核心。假设我们要添加列表中的所有元素。在过程代码中,通常会创建一个累加器变量并将其设置为0,然后遍历列表并按项递增累加器
在Ocaml中,您可以使用fold以功能性方式执行相同的操作:
List.fold_left (+) 0 [1; 2; 3];;
- : int = 6
例如,使用fold,您可以计算列表中的字数,并同时连接它们:
List.fold_left (fun (count, concat) e -> (count + 1, concat ^ e)) (0, "") ["a"; "b"; "c"];;
- : int * string = (3, "abc")
折叠的另一个有用用途是将向量复制到集合中。由于Ocaml中的集合是不可变的,因此实际上需要为列表中的每个项目创建一个新集合,其中包含上一个集合和该新项目
module Int = struct type t = int let compare = compare end;;
module IntSet = Set.Make(Int);;
let s = List.fold_left (fun set e -> IntSet.add e set) IntSet.empty [1; 2; 3];;
val s : IntSet.t = <abstr>
IntSet.elements s;;
- : IntSet.elt list = [1; 2; 3]
module Int=struct type t=Int let compare=compare end;;
模块IntSet=Set.Make(Int);;
让s=List.fold_left(乐趣集e->IntSet.add e set)IntSet.empty[1;2;3];;
val s:IntSet.t= PLEAC项目几乎正是以这一点为目标——用其他语言实现perl cookbook中的所有示例。这里是ocaml版本的链接(这是三个100%完成的版本之一)Snip第二个应该从map(str.upper,
开始,因为upper是str类的一个方法:str.upper.应该是社区wiki-没有“答案”就其本身而言?@Anthony,我希望有一个网站,但如果没有,那么我会创建这个。看起来你创建这个社区太快了-请查看pleac-o
let inline sort2 f i j (a:'a array) =
let i' = a.[ i ]
let j' = a.[ j ]
if f i' j' > 0 then
a.[ i ] <- j'
a.[ j ] <- i'
let bubble f (xs:'a array) =
if xs.Length = 0
then ()
let rec modified i endix =
if i = endix then
unmodified 0 (endix-1)
else
let j = i+1
sort2 f i j xs
modified j endix
and unmodified i endix =
if i = endix then
()
else
let j = i+1
let i' = xs.[ i ]
let j' = xs.[ j ]
if f i' j' > 0 then
xs.[ i ] <- j'
xs.[ j ] <- i'
modified j endix
else
unmodified j endix
in unmodified 0 (xs.Length-1)
let bubble_imperitive f (xs:'a array) =
let mutable bModified = true
let mutable endix = xs.Length - 1
while bModified do
bModified <- false
endix <- endix - 1
for i in 0..endix do
let j = i+1
let i' = xs.[ i ]
let j' = xs.[ j ]
if f i' j' > 0 then
xs.[ i ] <- j'
xs.[ j ] <- i'
bModified <- true
done
done
List.fold_left (+) 0 [1; 2; 3];;
- : int = 6
List.fold_left (fun (count, concat) e -> (count + 1, concat ^ e)) (0, "") ["a"; "b"; "c"];;
- : int * string = (3, "abc")
module Int = struct type t = int let compare = compare end;;
module IntSet = Set.Make(Int);;
let s = List.fold_left (fun set e -> IntSet.add e set) IntSet.empty [1; 2; 3];;
val s : IntSet.t = <abstr>
IntSet.elements s;;
- : IntSet.elt list = [1; 2; 3]