我想从一个音符和一个列表中创建一个和弦。
结构:
type objet_musical =
| Note of (int * int * int)
| Silence of int
| Sequence of objet_musical list
| Parallel of objet_musical list
和列表
let transposition = [(0,4,7);(0,3,7);(0,4,8);(0,3,6)];;
非常感谢你的回答。 玛丽
答案 0 :(得分:0)
应该在很短的步骤中解决大问题。首先让我们创建一个函数transpose_objet
,它将采用单个转置(即移位)的单个对象,并返回一个新对象,该对象按指定的移位以间距换位。
(** [transpose_objet obj shift] takes a musical object [obj] and
transposes it pitch to a value [shift] *)
let rec transpose_objet obj shift : objet_musical = match obj with
| Note (h,v,d) -> Note (h + shift, v, d)
| Silence t -> Silence t
| Sequence objs ->
Sequence (List.map (fun obj -> transpose_objet obj shift) objs)
| Parallel objs ->
Parallel (List.map (fun obj -> transpose_objet obj shift) objs)
接下来,让我们尝试创建三个换位的和弦。因此我们采用三元组和一个对象并行并行(我认为这就是和弦所代表的)。我们将此函数命名为chord_of_transposition
。
(** [chord_of_transposition obj tlist] takes a musical [obj] and a triplet,
where every element of triplet is a number to which the pitch
should be transposed, and creates a chord *)
let chord_of_transposition obj (t1,t2,t3) : objet_musical =
Parallel [transpose_objet obj t1;
transpose_objet obj t2;
transpose_objet obj t3]
通过这个方便的功能,我们可以处理一个组合三元组的列表。让我们写一个函数chords_of_transpositions
所以我们想要一个音乐对象和转置列表,并从每个转置创建一个和弦。我们希望它仍然是一个音乐对象,因此我们使用构造函数Sequence
从结果列表中创建一个对象。
(** [chords_of_transpositions obj transpositions] takes a list of
triplets, where each element of triplet is value by which a
musical object should be shifted and creates a sequence of musical
objects that will play a chords from each transposition. *)
let chords_of_transpositions obj ts : objet_musical =
Sequence (List.map (chord_of_transposition obj) ts)
作为练习,我建议你重写函数chord_of_composition
而不要重复丑陋(提示,请使用List.map
)。
作为第二个练习,尝试从transpose_objet
函数中删除代码重复。您是否注意到Parallel
和Sequence
子句的模式是相同的。
作为第三个练习,尝试重写您的代码,以便您的转置列表不是来自三元组,而是来自n-plets,如下所示:
let transposition = [[0;4;7];[0;3;7]; [0;8]; []; [0;3;6]]
其中空列表代表沉默。
我试试这个
let seq1= Sequence((Note(60,100,1000)):: (Note (64,100,500)):: (Note (62,100,500)):: (Silence(1000)):: (Note (67,100,1000)):: [])
和
let transposition= [(0,4,7);(0,3,7);(0,4,8);(0,3,6)];;
和你的主张
let chordify om tp : objet_musical= Sequence (List.map (chordify om)tp);;
和测试
让test = chordify seq1 transposition ;;
但顶级Ocaml返回
Error: This expression has type (int * int * int) list but an expression was expected of type int list list Type int * int * int is not compatible with type int list .
如何解决?
首先,我想指出,我们正在开始努力推动SO。这是一个问答网站,而不是论坛。我已经为你做了一些工作,但我没有看到,你正在努力做你自己的工作。我在这里不做你的功课,而是帮助你解决有关OCaml和编程的一般性问题。我的建议是从一本关于OCaml的好教科书开始,然后先学习它。只是尝试随机复制粘贴代码,直到编译不是一个好主意。现在,回到你的问题。
首先,不要像1 :: 2 :: 3 :: []
这样粗暴的方式构建列表,而是使用更加可靠的符号:[1;2;3]
。这样你的序列可以用以下方式重写:
let seq1 = Sequence [
Note (60,100,1000);
Note (64,100,500);
Note (62,100,500);
Silence (1000);
Note (67,100,1000)
]
接下来,您的功能
let chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
指的是一些未绑定的符号chordify
。如果你想在自己的体内调用一个函数,你需要使它递归,即将rec
添加到let
表达式中:
let rec chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
我认为,您已经将此功能两次推送到OCaml顶级,因此您实际上已经制定了followint定义。
let chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
let chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
但相反,你真正想要做的是,不要调用函数cordify
,而是调用函数chord_of_transposition
,它将转换objet_musical
对特定转置实例的转换,像这样:
let chordify om tp : objet_musical =
Sequence (List.map (chord_of_transposition om) tp)
因此,我们提出了一个与我之前提供的函数chords_of_transpositions
的定义相等的定义。