如何迭代具有相同类型的记录类型中的所有元素(记录类型的纯函数迭代器)
How to iterate over all elements in a record type with the same type (purely functional iterators for record types)
有没有一种很好的方法来迭代、折叠或循环记录中具有相同类型的所有元素?例如,在下面的 OCaml 代码中
type foo = {
a : int;
b : float;
c : int;
d : float
}
let foo = {
a = 1;
b = 2.0;
c = 3;
d = 4.0
}
我想分别遍历所有整数或浮点数。我知道 Fieldslib,但它似乎没有做我想做的事。例如,使用 Fieldslib,我可以编写代码:
open Fieldslib
type bar = {
w : int;
x : float;
y : int;
z : float
} with fields
let bar = {
w = 1;
x = 2.0;
y = 3;
z = 4.0
}
let print_int bar x = Printf.printf "%d\n" (Fieldslib.Field.get x bar)
let print_float bar x = Printf.printf "%f\n" (Fieldslib.Field.get x bar);;
Fields_of_bar.iter ~w:(print_int bar)
~x:(print_float bar)
~y:(print_int bar)
~z:(print_float bar)
但这迫使我们遍历所有元素,而不仅仅是单独的整数或浮点数。它还要求分别指定要在每个元素上调用的函数。真的,我只想说对结构进行迭代、映射或折叠某些函数。
如果异构记录类型很难做到这一点,那么所有元素都具有单一类型的记录类型会更容易吗?在这种情况下,我们可以定义一个镜头来投射出所有的整数、浮点数等。
从某种意义上说,感觉我想要某种与记录类型一起工作的纯函数迭代器,如果存在这种技术,我不确定它叫什么。
编辑 1
实际上,这可能比我想象的要简单得多。 Fieldslib 已经给出了第一个 class 个元素。只要我们列出所有具有相同类型的列表,我们就可以了。换句话说:
open Fieldslib
type bar = {
w : int;
x : float;
y : int;
z : float
} with fields
let ints=[w;y]
let floats=[x;z]
let bar = {
w = 1;
x = 2.0;
y = 3;
z = 4.0
};;
let print_ints bar = List.iter (fun l -> Printf.printf "%d\n" (l bar)) ints
let print_floats bar = List.iter (fun l -> Printf.printf "%f\n" (l bar)) floats
更一般地说,具有相同类型的镜头列表应该使所有这一切成为可能,因为我们可以只应用列表中的 map、fold 和 iter 函数。
编辑 2
如果有人想要 运行 @j-abrahamson 的代码,这里有一些轻微的修改,以便它 运行 在我的机器上
{-# LANGUAGE RankNTypes #-}
import Control.Applicative
import Control.Monad.Identity
data Foo = Foo {
a :: Int,
b :: Float,
c :: Int,
d :: Float
} deriving Show
type Traversal s a = forall f . Applicative f => (a -> f a) -> (s -> f s)
intsOfFoo :: Traversal Foo Int
intsOfFoo inj foo = build <$> inj (a foo) <*> inj (c foo) where
build a c = foo { a = a, c = c }
mapOf :: Traversal s a -> (a -> a) -> (s -> s)
mapOf trav f = runIdentity . trav (Identity . f)
foo0 = Foo { a = 1, b = 1, c = 1, d = 1 }
foo1 = mapOf intsOfFoo (+1) foo0
我还添加了 Haskell 标志,以防对其他人有所帮助。
实际上,这可能比我想象的要简单得多。 Fieldslib 已经给出了第一个 class 个元素。只要我们列出所有具有相同类型的列表,我们就可以了。换句话说:
open Fieldslib
type bar = {
w : int;
x : float;
y : int;
z : float
} with fields
let ints=[w;y]
let floats=[x;z]
let bar = {
w = 1;
x = 2.0;
y = 3;
z = 4.0
};;
let print_ints bar = List.iter (fun l -> Printf.printf "%d\n" (l bar)) ints
let print_floats bar = List.iter (fun l -> Printf.printf "%f\n" (l bar)) floats
更一般地说,具有相同类型的镜头列表应该使所有这一切成为可能,因为我们可以只应用列表中的映射、折叠和迭代函数。
作为半不相关的旁注,在 Haskell 中,这可以由 van Laarhoven Traversal
完成
data Foo = Foo {
a :: Int,
b :: Float,
c :: Int,
d :: Float
}
type Traversal s a = forall f . Applicative f => (a -> f a) -> (s -> f s)
intsOfFoo :: Traversal Foo Int
intsOfFoo inj foo = build <$> inj (a foo) <*> inj (b foo) where
build a b = foo { a = a, b = b }
这个值intsOfFoo
一般遍历Foo
用inj
函数接触每个int
并将这些"touches"的所有效果粉碎在一起重新-build
结果 Foo
.
mapOf :: Traversal s a -> (a -> a) -> (s -> s)
mapOf trav f = getIdentity . trav (Identity . f)
> let foo0 = Foo { a = 1, b = 1, c = 1, d = 1 }
> mapOf intsOfFoo (+1) foo0
Foo { a = 2, b = 1.0, c = 2, d = 1.0 }
不确定如何在 Fieldslib
中完成此操作,但这是 OCaml 中的丑陋草稿。
module type Applicative = sig
type 'a t
val map : ('a -> 'b) -> ('a t -> 'b t)
val pure : 'a -> 'a t
val ap : ('a -> 'b) t -> ('a t -> 'b t)
end
module type Traversal = functor (F : Applicative) ->
sig
type s
type a
val it : (a -> a F.t) -> (s -> s F.t)
end
module Identity = struct
type 'a t = 'a
let map f = f
let pure x = x
let ap f = f
end
module Traversals (T : Traversal) = struct
module Ti = T(Identity)
include Ti
let mapOf : (a -> a) -> (s -> s) = fun f s -> it f s
end
type foo = {
a : int;
b : float;
c : int;
d : float;
}
module TraverseFooInts (F : Applicative) = struct
let (<$>) = F.map
let (<*>) = F.ap
type s = foo
type a = int
let it inj foo =
let build a c = {foo with a = a; c = c} in
build <$> inj foo.a <*> inj foo.c
end
module Z = Traversals(TraverseFooInts)
最后,
# Z.mapOf;;
- : (int -> int) -> foo -> foo = <fun>
# Z.mapOf (fun x -> x + 1) { a = 1; b = 1.; c = 1; d = 1. };;
- : foo = {a = 2; b = 1.; c = 2; d = 1.}
有没有一种很好的方法来迭代、折叠或循环记录中具有相同类型的所有元素?例如,在下面的 OCaml 代码中
type foo = {
a : int;
b : float;
c : int;
d : float
}
let foo = {
a = 1;
b = 2.0;
c = 3;
d = 4.0
}
我想分别遍历所有整数或浮点数。我知道 Fieldslib,但它似乎没有做我想做的事。例如,使用 Fieldslib,我可以编写代码:
open Fieldslib
type bar = {
w : int;
x : float;
y : int;
z : float
} with fields
let bar = {
w = 1;
x = 2.0;
y = 3;
z = 4.0
}
let print_int bar x = Printf.printf "%d\n" (Fieldslib.Field.get x bar)
let print_float bar x = Printf.printf "%f\n" (Fieldslib.Field.get x bar);;
Fields_of_bar.iter ~w:(print_int bar)
~x:(print_float bar)
~y:(print_int bar)
~z:(print_float bar)
但这迫使我们遍历所有元素,而不仅仅是单独的整数或浮点数。它还要求分别指定要在每个元素上调用的函数。真的,我只想说对结构进行迭代、映射或折叠某些函数。
如果异构记录类型很难做到这一点,那么所有元素都具有单一类型的记录类型会更容易吗?在这种情况下,我们可以定义一个镜头来投射出所有的整数、浮点数等。
从某种意义上说,感觉我想要某种与记录类型一起工作的纯函数迭代器,如果存在这种技术,我不确定它叫什么。
编辑 1
实际上,这可能比我想象的要简单得多。 Fieldslib 已经给出了第一个 class 个元素。只要我们列出所有具有相同类型的列表,我们就可以了。换句话说:
open Fieldslib
type bar = {
w : int;
x : float;
y : int;
z : float
} with fields
let ints=[w;y]
let floats=[x;z]
let bar = {
w = 1;
x = 2.0;
y = 3;
z = 4.0
};;
let print_ints bar = List.iter (fun l -> Printf.printf "%d\n" (l bar)) ints
let print_floats bar = List.iter (fun l -> Printf.printf "%f\n" (l bar)) floats
更一般地说,具有相同类型的镜头列表应该使所有这一切成为可能,因为我们可以只应用列表中的 map、fold 和 iter 函数。
编辑 2
如果有人想要 运行 @j-abrahamson 的代码,这里有一些轻微的修改,以便它 运行 在我的机器上
{-# LANGUAGE RankNTypes #-}
import Control.Applicative
import Control.Monad.Identity
data Foo = Foo {
a :: Int,
b :: Float,
c :: Int,
d :: Float
} deriving Show
type Traversal s a = forall f . Applicative f => (a -> f a) -> (s -> f s)
intsOfFoo :: Traversal Foo Int
intsOfFoo inj foo = build <$> inj (a foo) <*> inj (c foo) where
build a c = foo { a = a, c = c }
mapOf :: Traversal s a -> (a -> a) -> (s -> s)
mapOf trav f = runIdentity . trav (Identity . f)
foo0 = Foo { a = 1, b = 1, c = 1, d = 1 }
foo1 = mapOf intsOfFoo (+1) foo0
我还添加了 Haskell 标志,以防对其他人有所帮助。
实际上,这可能比我想象的要简单得多。 Fieldslib 已经给出了第一个 class 个元素。只要我们列出所有具有相同类型的列表,我们就可以了。换句话说:
open Fieldslib
type bar = {
w : int;
x : float;
y : int;
z : float
} with fields
let ints=[w;y]
let floats=[x;z]
let bar = {
w = 1;
x = 2.0;
y = 3;
z = 4.0
};;
let print_ints bar = List.iter (fun l -> Printf.printf "%d\n" (l bar)) ints
let print_floats bar = List.iter (fun l -> Printf.printf "%f\n" (l bar)) floats
更一般地说,具有相同类型的镜头列表应该使所有这一切成为可能,因为我们可以只应用列表中的映射、折叠和迭代函数。
作为半不相关的旁注,在 Haskell 中,这可以由 van Laarhoven Traversal
data Foo = Foo {
a :: Int,
b :: Float,
c :: Int,
d :: Float
}
type Traversal s a = forall f . Applicative f => (a -> f a) -> (s -> f s)
intsOfFoo :: Traversal Foo Int
intsOfFoo inj foo = build <$> inj (a foo) <*> inj (b foo) where
build a b = foo { a = a, b = b }
这个值intsOfFoo
一般遍历Foo
用inj
函数接触每个int
并将这些"touches"的所有效果粉碎在一起重新-build
结果 Foo
.
mapOf :: Traversal s a -> (a -> a) -> (s -> s)
mapOf trav f = getIdentity . trav (Identity . f)
> let foo0 = Foo { a = 1, b = 1, c = 1, d = 1 }
> mapOf intsOfFoo (+1) foo0
Foo { a = 2, b = 1.0, c = 2, d = 1.0 }
不确定如何在 Fieldslib
中完成此操作,但这是 OCaml 中的丑陋草稿。
module type Applicative = sig
type 'a t
val map : ('a -> 'b) -> ('a t -> 'b t)
val pure : 'a -> 'a t
val ap : ('a -> 'b) t -> ('a t -> 'b t)
end
module type Traversal = functor (F : Applicative) ->
sig
type s
type a
val it : (a -> a F.t) -> (s -> s F.t)
end
module Identity = struct
type 'a t = 'a
let map f = f
let pure x = x
let ap f = f
end
module Traversals (T : Traversal) = struct
module Ti = T(Identity)
include Ti
let mapOf : (a -> a) -> (s -> s) = fun f s -> it f s
end
type foo = {
a : int;
b : float;
c : int;
d : float;
}
module TraverseFooInts (F : Applicative) = struct
let (<$>) = F.map
let (<*>) = F.ap
type s = foo
type a = int
let it inj foo =
let build a c = {foo with a = a; c = c} in
build <$> inj foo.a <*> inj foo.c
end
module Z = Traversals(TraverseFooInts)
最后,
# Z.mapOf;;
- : (int -> int) -> foo -> foo = <fun>
# Z.mapOf (fun x -> x + 1) { a = 1; b = 1.; c = 1; d = 1. };;
- : foo = {a = 2; b = 1.; c = 2; d = 1.}