Loops 我如何从一个函数返回一个值,该函数在F中迭代for循环#
我尝试在数组上循环并返回如下所示的值。但是这在if语句后面的行中给了我一个错误。它表示“此表达式应具有类型unit,但具有类型int”Loops 我如何从一个函数返回一个值,该函数在F中迭代for循环#,loops,f#,functional-programming,Loops,F#,Functional Programming,我尝试在数组上循环并返回如下所示的值。但是这在if语句后面的行中给了我一个错误。它表示“此表达式应具有类型unit,但具有类型int” 我该怎么做?我正在用递归循环来记录这个循环,因为它似乎是在函数语言中这样循环的更被接受的方式,但是我仍然想知道上面我做了什么错误。 循环不应该返回值,它们只做固定次数的操作,然后返回() >(单元)。如果要迭代并最终返回某些内容,可以: 在循环外部有一个引用,当你得到最终结果时,你把它放在那里,然后在循环之后返回引用内容 直接使用递归函数 使用一个高阶函数
我该怎么做?我正在用递归循环来记录这个循环,因为它似乎是在函数语言中这样循环的更被接受的方式,但是我仍然想知道上面我做了什么错误。 <代码> 循环不应该返回值,它们只做固定次数的操作,然后返回<代码>()<代码> >(单元)。如果要迭代并最终返回某些内容,可以:
- 在循环外部有一个引用,当你得到最终结果时,你把它放在那里,然后在循环之后返回引用内容
- 直接使用递归函数
- 使用一个高阶函数来封装遍历,并让您专注于应用程序逻辑
fold_left
等简单遍历函数不支持过早停止迭代。如果您希望支持这一点(显然在您的用例中它会很有趣),您必须使用带有过早退出支持的遍历。对于像您这样的简单函数,简单的递归函数可能是最简单的
在F#中,也可以用命令式风格编写函数,使用yield
将函数转换为生成器,然后最终强制生成器获得结果。这可以看作是使用异常跳出循环的OCaml技术的一种对应
编辑:避免“过早停止”问题的一个很好的解决方案是使用一个惰性的中间数据结构,它只会构建到第一个令人满意的结果。这是一种优雅且良好的脚本风格,但仍然不如直接退出支持或简单递归有效。我想这取决于你的需要;此功能是否用于关键路径
编辑:以下是一些代码示例。它们是OCaml,数据结构不同(其中一些使用来自的库),但思想是相同的
(* using a reference as accumulator *)
let most_significant_bit input_bits =
let result = ref None in
for i = Array.length input_bits - 1 downto 0 do
if input_bits.(i) then
if !result = None then
result := Some i
done;
!result
let most_significant_bit input_bits =
let result = ref None in
for i = 0 to Array.length input_bits - 1 do
if input_bits.(i) then
(* only the last one will be kept *)
result := Some i
done;
!result
(* simple recursive version *)
let most_significant_bit input_bits =
let rec loop = function
| -1 -> None
| i ->
if input_bits.(i) then Some i
else loop (i - 1)
in
loop (Array.length input_bits - 1)
(* higher-order traversal *)
open Batteries_uni
let most_significant_bit input_bits =
Array.fold_lefti
(fun result i ->
if input_bits.(i) && result = None then Some i else result)
None input_bits
(* traversal using an intermediate lazy data structure
(a --- b) is the decreasing enumeration of integers in [b; a] *)
open Batteries_uni
let most_significant_bit input_bits =
(Array.length input_bits - 1) --- 0
|> Enum.Exceptionless.find (fun i -> input_bits.(i))
(* using an exception to break out of the loop; if I understand
correctly, exceptions are rather discouraged in F# for efficiency
reasons. I proposed to use `yield` instead and then force the
generator, but this has no direct OCaml equivalent. *)
exception Result of int
let most_significant_bit input_bits =
try
for i = Array.length input_bits - 1 downto 0 do
if input_bits.(i) then raise (Result i)
done;
None
with Result i -> Some i
+1个用于加气下面是F#中的一些例子。我添加了一个(第二个)来显示
yield
如何与序列表达式中的for
一起工作,如gasche所述
(* using a mutable variable as accumulator as per gasche's example *)
let findMostSignificantBitPosition (inputBits: BitArray) =
let mutable ret = None // 0
for i = inputBits.Length - 1 downto 0 do
if inputBits.[i] then ret <- i
ret
(* transforming to a Seq of integers with a for, then taking the first element *)
let findMostSignificantBitPosition2 (inputBits: BitArray) =
seq {
for i = 0 to inputBits.Length - 1 do
if inputBits.[i] then yield i
} |> Seq.head
(* casting to a sequence of bools then taking the index of the first "true" *)
let findMostSignificantBitPosition3 (inputBits: BitArray) =
inputBits|> Seq.cast<bool> |> Seq.findIndex(fun f -> f)
(*根据gasche的示例*使用可变变量作为累加器)
让findMostSignificantBitPosition(输入位:位数组)=
设可变ret=None//0
对于i=输入位。长度-1到0
如果输入位为[i],则返回序列头
(*强制转换为一系列布尔值,然后获取第一个“true”的索引*)
让findMostSignificantBitPosition3(输入位:位数组)=
inputBits |>Seq.cast |>Seq.findIndex(乐趣f->f)
编辑:返回选项的版本
let findMostSignificantBitPosition (inputBits: BitArray) =
let mutable ret = None
for i = inputBits.Length - 1 downto 0 do
if inputBits.[i] then ret <- Some i
ret
let findMostSignificantBitPosition2 (inputBits: BitArray) =
seq {
for i = 0 to inputBits.Length - 1 do
if inputBits.[i] then yield Some(i)
else yield None
} |> Seq.tryPick id
let findMostSignificantBitPosition3 (inputBits: BitArray) =
inputBits|> Seq.cast<bool> |> Seq.tryFindIndex(fun f -> f)
让findMostSignificantBitPosition(输入位:位数组)=
设可变ret=None
对于i=输入位。长度-1到0
如果输入位为[i],则返回Seq.tryPick id
让findMostSignificantBitPosition3(输入位:位数组)=
输入位|>顺序cast |>顺序tryFindIndex(乐趣f->f)
既然可以使用高阶函数,为什么还要使用循环
我会写:
let findMostSignificantBitPosition (inputBits:System.Collections.BitArray) =
Seq.cast<bool> inputBits |> Seq.tryFindIndex id
让findMostSignificantBitPosition(输入位:System.Collections.BitArray)=
Seq.cast inputBits |>Seq.tryFindIndex id
Seq
模块包含许多用于操作集合的函数。它通常是使用命令式循环的一个很好的替代方法
但我还是想知道我是什么
在上面做错事
for
循环的主体是unit类型的表达式。你唯一能做的就是做副作用(修改可变值,打印…)
在F#中,a
if-then-else
类似于?:代码>来自C语言。then
和else
部分必须具有相同的类型,否则在使用静态类型的语言中没有意义。当else
丢失时,编译器会假定它是else()
。因此,然后
必须具有类型单元
。将值放入循环中并不意味着返回,因为一切都是F#中的值(包括if-then
)。我建议使用高阶函数(如Laurent所述)或显式编写递归函数(这是替换F#中循环的一般方法)
如果您想看到一些奇特的F#解决方案(这可能是使用临时惰性数据结构的更好版本),那么您可以看看我的文章,其中定义了F#。这允许您编写以下内容:
let findMostSignificantBitPosition (inputBits:BitArray) = imperative {
for b in Seq.cast<bool> inputBits do
if b then return true
return false }
让findMostSignificantBitPosition(inputBits:BitArray)=命令{
对于顺序中的b,铸造输入位do
如果b,则返回true
返回false}
有一些开销(与使用其他临时惰性数据结构一样),但它看起来就像C#:-)。
编辑我还将示例发布在F#Snippets上:我认为您在如何编写此代码方面遇到问题的原因是您没有处理找不到设置位的失败案例。其他人则发布了许多找到比特的方法。下面是一些处理失败案例的方法
按选项列出故障案例
let findMostSignificantBitPosition (inputBits:System.Collections.BitArray) =
let rec loop i =
if i = -1 then
None
elif inputBits.[i] then
Some i
else
loop (i - 1)
loop (inputBits.Length - 1)
let test = new BitArray(1)
match findMostSignificantBitPosition test with
| Some i -> printf "Most Significant Bit: %i" i
| None -> printf "Most Significant Bit Not Found"
异常情况下的故障
let findMostSignificantBitPosition (inputBits:System.Collections.BitArray) =
let rec loop i =
if i = -1 then
failwith "Most Significant Bit Not Found"
elif inputBits.[i] then
i
else
loop (i - 1)
loop (inputBits.Length - 1)
let test = new BitArray(1)
try
let i = findMostSignificantBitPosition test
printf "Most Significant Bit: %i" i
with
| Failure msg -> printf "%s" msg
故障案例-1
let findMostSignificantBitPosition (inputBits:System.Collections.BitArray) =
let rec loop i =
if i = -1 then
i
elif inputBits.[i] then
i
else
loop (i - 1)
loop (inputBits.Length - 1)
let test = new BitArray(1)
let i = findMostSignificantBitPosition test
if i <> -1 then
printf "Most Significant Bit: %i" i
else
printf "Most Significant Bit Not Found"
让findMostSignificantBitPosition(输入位:System.Collections.BitArray)=
让rec循环一次=
如果i=-1,那么
我
elif inputBits[i]然后
我
其他的
回路(i-1)
循环(inputBits.Length-1)
let test=新的位数组(1)
设i=findMostSignificantBitPosition测试
如果i-1那么
printf“最高有效位:%i”i
其他的
printf“Most标志”
let findMostSignificantBitPosition (inputBits:System.Collections.BitArray) =
let rec loop i =
if i = -1 then
i
elif inputBits.[i] then
i
else
loop (i - 1)
loop (inputBits.Length - 1)
let test = new BitArray(1)
let i = findMostSignificantBitPosition test
if i <> -1 then
printf "Most Significant Bit: %i" i
else
printf "Most Significant Bit Not Found"
let findMostSignificantBitPosition (inputBits:System.Collections.BitArray) =
seq {
for i = inputBits.Length - 1 to 0 do
yield inputBits.[i]
} |> Seq.findIndex(fun e -> e)