思考在 Elm 中看到的模式名称以及其他类似情况
Pondering name of pattern seen in Elm and if other similar cases
我目前是FP的学生。当我查看不同功能语言提供的不同语法时,我在 Elm 示例代码中遇到了一个模式。我很好奇。
这里是示例代码
myList = [{foo = "bar1"},{foo = "bar2"}]
foos = myList |> List.map .foo
在这里的最后一行,List.map
被传递 .foo
。我相信这种风格被称为无点,但是将属性传递给 List.map
函数的具体模式呢?
这是比较常见的事情吗?是否可以在 Haskell 中执行此操作? F#?斯卡拉?感谢您的帮助。
此处模式的正式(或非正式)名称是什么(或是否有)?一个对象的 属性 用作一个函数的简写,该函数接受一个对象并在其上调用 said 属性?
如果您将列表视为"dataset"或"table",并将列表中的每个元素视为"row",并且定义元素的数据类型作为"attributes"的枚举,那么得到的是一种关系代数意义上的"projection":https://en.wikipedia.org/wiki/Projection_(relational_algebra).
这是一个 Scala 示例,感觉有点 SQL-ish:
case class Row(id: Int, name: String, surname: String, age: Int)
val data = List(
Row(0, "Bob", "Smith", 25),
Row(1, "Charles", "Miller", 35),
Row(2, "Drew", "Shephard", 45),
Row(3, "Evan", "Bishop", 55)
)
val surnames = data map (_.surname)
val ages = data map (_.age)
val selectIdName = data map { row => (row.id, row.name) }
println(surnames)
// List(Smith, Miller, Shephard, Bishop)
println(selectIdName)
// List((0,Bob), (1,Charles), (2,Drew), (3,Evan))
此处,_.fieldName
是 Row => TypeOfTheField
.
类型的内联函数文字的简短语法
在 Haskell 中有点微不足道,因为记录数据类型的声明会自动将所有 getter 函数带入作用域:
data Row = Row { id :: Int
, name :: String
, surname :: String
, age :: Int
} deriving Show
main = let dataset = [ Row 0 "Bob" "Smith" 25
, Row 1 "Charles" "Miller" 35
, Row 2 "Drew" "Shephard" 45
, Row 3 "Evan" "Bishop" 55
]
in print $ map name dataset
-- prints ["Bob","Charles","Drew","Evan"]
甚至 Java 自版本 8 以来也有类似的东西:
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
class JavaProjectionExample {
private static class Row {
private final int id;
private final String name;
private final String surname;
private final int age;
public Row(int id, String name, String surname, int age) {
super();
this.id = id;
this.name = name;
this.surname = surname;
this.age = age;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public int getAge() {
return this.age;
}
}
public static void main(String[] args) {
List<Row> data = Arrays.asList(
new Row(0, "Bob", "Smith", 25),
new Row(1, "Charles", "Miller", 35),
new Row(2, "Drew", "Shephard", 45),
new Row(3, "Evan", "Bishop", 55)
);
List<Integer> ids = data.stream().map(Row::getId).collect(toList());
List<String> names = data.stream().map(Row::getName).collect(toList());
System.out.println(ids);
System.out.println(names);
}
}
这里,Row::getterName
是getter方法的特殊语法,是Function<Row, FieldType>
.
类型的值
这实际上不是无意义的,而是语法糖和管道转发运算符。对于免费积分,请参阅 this article。
这可以用fsharp写成如下:
let foos = myList |> List.map (fun x -> x.foo)
你可以立即看出这等同于
List.map (fun x -> x.foo) myList
所以管道运算符只是翻转参数并使将操作链接在一起变得容易。因此,您将函数和列表传递给地图。 Elm 中的语法糖允许您跳过函数参数,只需写出 .foo。顺便说一句,我认为该功能非常方便。
当您避免指定函数的参数时,无点将是。它是典型的 FP,但一旦变得复杂就很难阅读。
一个例子:
let mySum x y = x + y
//val mySum : x:int -> y:int -> int
mySum 4 7 //11
这是免费积分:
let mySum2 = (+)
//val mySum2 : (int -> int -> int)
mySum2 4 7 //11
我目前是FP的学生。当我查看不同功能语言提供的不同语法时,我在 Elm 示例代码中遇到了一个模式。我很好奇。
这里是示例代码
myList = [{foo = "bar1"},{foo = "bar2"}]
foos = myList |> List.map .foo
在这里的最后一行,List.map
被传递 .foo
。我相信这种风格被称为无点,但是将属性传递给 List.map
函数的具体模式呢?
这是比较常见的事情吗?是否可以在 Haskell 中执行此操作? F#?斯卡拉?感谢您的帮助。
此处模式的正式(或非正式)名称是什么(或是否有)?一个对象的 属性 用作一个函数的简写,该函数接受一个对象并在其上调用 said 属性?
如果您将列表视为"dataset"或"table",并将列表中的每个元素视为"row",并且定义元素的数据类型作为"attributes"的枚举,那么得到的是一种关系代数意义上的"projection":https://en.wikipedia.org/wiki/Projection_(relational_algebra).
这是一个 Scala 示例,感觉有点 SQL-ish:
case class Row(id: Int, name: String, surname: String, age: Int)
val data = List(
Row(0, "Bob", "Smith", 25),
Row(1, "Charles", "Miller", 35),
Row(2, "Drew", "Shephard", 45),
Row(3, "Evan", "Bishop", 55)
)
val surnames = data map (_.surname)
val ages = data map (_.age)
val selectIdName = data map { row => (row.id, row.name) }
println(surnames)
// List(Smith, Miller, Shephard, Bishop)
println(selectIdName)
// List((0,Bob), (1,Charles), (2,Drew), (3,Evan))
此处,_.fieldName
是 Row => TypeOfTheField
.
在 Haskell 中有点微不足道,因为记录数据类型的声明会自动将所有 getter 函数带入作用域:
data Row = Row { id :: Int
, name :: String
, surname :: String
, age :: Int
} deriving Show
main = let dataset = [ Row 0 "Bob" "Smith" 25
, Row 1 "Charles" "Miller" 35
, Row 2 "Drew" "Shephard" 45
, Row 3 "Evan" "Bishop" 55
]
in print $ map name dataset
-- prints ["Bob","Charles","Drew","Evan"]
甚至 Java 自版本 8 以来也有类似的东西:
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
class JavaProjectionExample {
private static class Row {
private final int id;
private final String name;
private final String surname;
private final int age;
public Row(int id, String name, String surname, int age) {
super();
this.id = id;
this.name = name;
this.surname = surname;
this.age = age;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public int getAge() {
return this.age;
}
}
public static void main(String[] args) {
List<Row> data = Arrays.asList(
new Row(0, "Bob", "Smith", 25),
new Row(1, "Charles", "Miller", 35),
new Row(2, "Drew", "Shephard", 45),
new Row(3, "Evan", "Bishop", 55)
);
List<Integer> ids = data.stream().map(Row::getId).collect(toList());
List<String> names = data.stream().map(Row::getName).collect(toList());
System.out.println(ids);
System.out.println(names);
}
}
这里,Row::getterName
是getter方法的特殊语法,是Function<Row, FieldType>
.
这实际上不是无意义的,而是语法糖和管道转发运算符。对于免费积分,请参阅 this article。
这可以用fsharp写成如下:
let foos = myList |> List.map (fun x -> x.foo)
你可以立即看出这等同于
List.map (fun x -> x.foo) myList
所以管道运算符只是翻转参数并使将操作链接在一起变得容易。因此,您将函数和列表传递给地图。 Elm 中的语法糖允许您跳过函数参数,只需写出 .foo。顺便说一句,我认为该功能非常方便。
当您避免指定函数的参数时,无点将是。它是典型的 FP,但一旦变得复杂就很难阅读。
一个例子:
let mySum x y = x + y
//val mySum : x:int -> y:int -> int
mySum 4 7 //11
这是免费积分:
let mySum2 = (+)
//val mySum2 : (int -> int -> int)
mySum2 4 7 //11