2017-01-21 11 views
0

Я сделал запись, называемую автоматом, содержащую 5 полей, необходимых для представления автомата. Я должен использовать графику для представления каждого состояние и переход из списка переходов без использования для или во время циклов только рекурсивные функцийКак я могу представить автомат графически из списка int * char * int, представляющего переходы без использования циклов

transitions :(int*char*int) list; 

ответ

3

Это может быть простым в использовании graphviz сделать фактический рисунок. Он автоматически рисует график из списка узлов и ребер, что и является вашим входом. Функция fmt_transition генерирует один ребро, функция fmt_transitions поднимает его через pp_print_list в списки переходов и завертывает его в правильный заголовок.

let fmt_transition fmt (inedge,by,outedge) = 
    Format.fprintf fmt "@[%d -> %d [label=\"%c\"];@]" inedge outedge by 

let fmt_transitions fmt = 
    Format.fprintf fmt "@[<v 2>digraph output {@,%[email protected],@]}@,@." 
    (Format.pp_print_list fmt_transition) 

Если попробовать на некоторых тестовых данных, мы получаем тестовый файл, который мы хотели:

let test1 = [ (1,'a',2); (2,'b',1); (1,'b',1)] in 
fmt_transitions Format.std_formatter test1;; 

результаты в:

digraph output 
{ 
    1 -> 2 [label="a"]; 
    2 -> 1 [label="b"]; 
    1 -> 1 [label="b"]; 
} 

Вызов GraphViz является:

dot -T pdf -o output.pdf < input.dot 

Если вы вызываете это прямо из ocaml, вы можете также перенесите данные непосредственно в точку, не записывая их сначала на диск.

В качестве альтернативы, вы можете также использовать внешнюю программу просмотр, как ГВ:

let call_dot data = 
    let cmd = "dot -Tps | gv -" in 
    let (sout, sin, serr) as channels = 
    Unix.open_process_full cmd (Unix.environment()) in 
    let fmt = Format.formatter_of_out_channel sin in 
    Format.fprintf fmt "%[email protected]" fmt_transitions data; 
    channels 

let cleanup channels = 
    (* missing: flush channels, empty buffers *) 
    Unix.close_process_full channels 

Вызов call_dot test1 |> cleanup будет посылать данные точки и открытой Ghostview. Чтобы не допустить предела открытых файлов, один крик ждет завершения процесса и закрытия каналов, что делается в cleanup.

Если вы хотите использовать библиотеку изображений вместо этого, вы можете заменить определение cmd на «dot -Tpng» и прочитать данные изображения из stdin перед вызовом очистки.

+0

Я знаю, что проще использовать graphviz, но есть способ, чтобы я мог использовать только графический модуль ocaml, возможно, с рекурсивной функцией, которая действует на элементы списка или может быть более одной функции –

+0

, а также я бы например, я не нашел способ вывода файла, сгенерированного ocaml из ocaml. –

+0

. Как вы продолжаете, зависит от ваших дальнейших планов - для статических данных может быть достаточно многоточия вывода точек в evince/ghostview. Если вам нужен пользовательский интерфейс, вы можете создать образ вместо него и использовать привязки gtk ocaml. Также есть [ocamlgraph] (https://github.com/backtracking/ocamlgraph), но у меня нет опыта с ним. В худшем случае вы можете использовать вывод аннотации для графического объекта, чтобы найти хорошее размещение для узлов, а остальные - с помощью функций рисования с низким уровнем в холсте gdk. –