从 Python 转换为 F# 递归函数?
Converting from Python to F# recursive function?
我试图在不使用不可变变量或 List.map
的情况下将此 Python 代码转换为 F#。我还是个新手。
def findMatches(s,l):
temp=[]
for i in l:
if i[0]==s:
temp.append(i[1])
temp.sort()
return temp
l=findMatches("A",[("A",5),("AA",9),("BB",6),("A",0)])
print(l)
我开始于:
let findMatches s l =
for e1, e2 in list do
if e1 = s then ...
如果我正朝着正确的方向前进或下一步要去哪里,则不完全是。
在 Python 中,在进行过程中改变 ("change"、"update") 数据是一种常见的做法 - 就像您对 temp
列表,在每一步都改变它。虽然即使在 Python 中也普遍不被接受,但语言本身使其变得非常简单,因此非常诱人。
在 F# 中改变数据仍然是可能的,但语言让它变得困难。故意。好吧,没有 难 - 这只是一些额外的字符,但至少变异数据不是默认设置。这通常是一种更好的方法,甚至 Python 社区现在也承认这一点。
相反,F# 方式(一般而言,函数式 方式)不是改变数据,而是通过转换旧数据来创建新数据。比如,函数的作用("functions" 我的意思是 "mathematical functions")。
特别是,您的 Python 循环似乎正在做的是 (1) 通过 i[0]
过滤 输入列表,然后 (2) 转换(通常称为"mapping")每个元素通过扔掉i[0]
只留下i[1]
,然后(3)排序。这可以用 F# 写成这样:
let findMatches s l =
l
|> List.filter (fun (e1, _) -> e1 == s) // filtering
|> List.map (fun (_, e2) -> e2) // mapping
|> List.sort
此程序不是通过重复修改列表来 "building up" 列表,而是通过三次转换输入列表来创建结果列表:过滤、映射、排序。另外需要注意的是,转换本身是由更小的部分构建的:整个列表的转换是通过转换单个元素的转换来实现的。
对于像这样的简单情况(排序除外),F# 还提供了特殊语法 - 即所谓的 "list comprehensions"。它是语法糖,在幕后执行类似于上述的转换,但语法(可以说)更具可读性:
let findMatches s l =
[ for e1, e2 in l do
if e1 == s then yield e2
]
|> List.sort
请注意,虽然这看起来与您的 Python 程序几乎相同,但含义略有不同。该程序不是 "do this, then do that"(又名 "imperative style"),而是 "the result depends on the input in this way"(又名 "functional style")。
我能想到的从Python示例代码到F#的最直接映射:
// I tend to specify the signatures of methods as I find it helpful
let findMatches (s : 'K) (l : seq<'K*'V>): seq<'V> =
// ResizeArray is an alias for System.Collections.Generic.List<_>
let temp = ResizeArray ()
for e1, e2 in l do
if e1 = s then
temp.Add e2
temp.Sort ()
// F# don't do implicit upcasts like C# so an explicit upcast from
// ResizeArray to seq
upcast temp
正如 Fyodor 在 F# 中提到的那样,习惯用法(即常用方法)是为了避免可变性并更喜欢内置的高阶函数(如过滤器和映射)来处理列表。
我试图在不使用不可变变量或 List.map
的情况下将此 Python 代码转换为 F#。我还是个新手。
def findMatches(s,l):
temp=[]
for i in l:
if i[0]==s:
temp.append(i[1])
temp.sort()
return temp
l=findMatches("A",[("A",5),("AA",9),("BB",6),("A",0)])
print(l)
我开始于:
let findMatches s l =
for e1, e2 in list do
if e1 = s then ...
如果我正朝着正确的方向前进或下一步要去哪里,则不完全是。
在 Python 中,在进行过程中改变 ("change"、"update") 数据是一种常见的做法 - 就像您对 temp
列表,在每一步都改变它。虽然即使在 Python 中也普遍不被接受,但语言本身使其变得非常简单,因此非常诱人。
在 F# 中改变数据仍然是可能的,但语言让它变得困难。故意。好吧,没有 难 - 这只是一些额外的字符,但至少变异数据不是默认设置。这通常是一种更好的方法,甚至 Python 社区现在也承认这一点。
相反,F# 方式(一般而言,函数式 方式)不是改变数据,而是通过转换旧数据来创建新数据。比如,函数的作用("functions" 我的意思是 "mathematical functions")。
特别是,您的 Python 循环似乎正在做的是 (1) 通过 i[0]
过滤 输入列表,然后 (2) 转换(通常称为"mapping")每个元素通过扔掉i[0]
只留下i[1]
,然后(3)排序。这可以用 F# 写成这样:
let findMatches s l =
l
|> List.filter (fun (e1, _) -> e1 == s) // filtering
|> List.map (fun (_, e2) -> e2) // mapping
|> List.sort
此程序不是通过重复修改列表来 "building up" 列表,而是通过三次转换输入列表来创建结果列表:过滤、映射、排序。另外需要注意的是,转换本身是由更小的部分构建的:整个列表的转换是通过转换单个元素的转换来实现的。
对于像这样的简单情况(排序除外),F# 还提供了特殊语法 - 即所谓的 "list comprehensions"。它是语法糖,在幕后执行类似于上述的转换,但语法(可以说)更具可读性:
let findMatches s l =
[ for e1, e2 in l do
if e1 == s then yield e2
]
|> List.sort
请注意,虽然这看起来与您的 Python 程序几乎相同,但含义略有不同。该程序不是 "do this, then do that"(又名 "imperative style"),而是 "the result depends on the input in this way"(又名 "functional style")。
我能想到的从Python示例代码到F#的最直接映射:
// I tend to specify the signatures of methods as I find it helpful
let findMatches (s : 'K) (l : seq<'K*'V>): seq<'V> =
// ResizeArray is an alias for System.Collections.Generic.List<_>
let temp = ResizeArray ()
for e1, e2 in l do
if e1 = s then
temp.Add e2
temp.Sort ()
// F# don't do implicit upcasts like C# so an explicit upcast from
// ResizeArray to seq
upcast temp
正如 Fyodor 在 F# 中提到的那样,习惯用法(即常用方法)是为了避免可变性并更喜欢内置的高阶函数(如过滤器和映射)来处理列表。