thedeemon: (Default)
[personal profile] thedeemon
Раз все молчат, напишу я. На днях вышел Окамл 4.0, в котором появились GADT. Рассказать о них можно на классическом примере: AST. Пусть у нас есть язычок с целыми числами, которые можно складывать и сравнивать. Результат сложения - целое число, результат сравнения - булев. Есть выражение if, в котором должно быть булево условие и пара выражений одинакового типа. Раньше, если мы все выражения этого язычка описали бы одним типом, то булевы и численные выражения оказались бы взаимозаменяемы, и проверку типов пришлось бы встраивать в интерпретатор, делать ее в рантайме. Если разнести численные и булевы выражения по разным типам, то можно было бы статически гарантировать, что условие в if'e точно будет булевым выражением, но пришлось бы делать разные функции для интерпретации и других операций над AST - как минимум одну для булевых выражений и одну для численных. С GADT можно все описать одним типом и одной функцией, не потеряв статических гарантий:
type 'a expr =  
  | I   : int -> int expr 
  | Add : int expr * int expr -> int expr 
  | Gt  : int expr * int expr -> bool expr 
  | If  : bool expr * 'a expr * 'a expr -> 'a expr;; 
 
let rec eval : type a . a expr -> a = function 
  | I n -> n 
  | Add(e1, e2) -> eval e1 + eval e2 
  | Gt(e1, e2)  -> eval e1 > eval e2 
  | If(cond, thn, els) -> if eval cond then eval thn else eval els;; 

Тип expr устроен таким образом, что в условии у if'a может оказаться только булево выражение, а складываться и сравниваться могут только численные. При этом функция eval для целочисленных выражений возвращает int, а для булевых - bool:
 
let e1 = If( Gt( Add(I 5, I 2), I 6 ),  I 1, I 0) in 
let b = Gt(I 1, I 2) in 
let e2 = If(b, b, b) in 
print_int (eval e1); 
Printf.printf " %b" (eval e2);; 

Результат вычисления выражения if имеет тот же тип, что оба подвыражения-ветки, причем их тип должен быть одинаковым, иначе компилятор не даст построить такое if-выражение.

А какие полезные применения GADT'ам знаете вы?

Date: 2012-07-30 11:57 am (UTC)
From: [identity profile] isorecursive.livejournal.com
В Hoopl их изящно используют - для описания открыто-закрытости форм потока управления:
http://hackage.haskell.org/packages/archive/hoopl/3.8.7.4/doc/html/src/Compiler-Hoopl-Graph.html#O

For example,
• A shift-left instruction is open on entry (because control can
fall into it from the preceding instruction), and open on exit
(because control falls through to the next instruction).
• An unconditional branch is open on entry, but closed on exit
(because control cannot fall through to the next instruction).
• A label is closed on entry (because in Hoopl we do not allow
control to fall through into a branch target), but open on exit.

http://research.microsoft.com/en-us/um/people/simonpj/papers/c--/dfopt.pdf
http://blog.ezyang.com/2011/04/hoopl-guided-tour-base-system/

Profile

thedeemon: (Default)
Dmitry Popov

February 2026

S M T W T F S
12 34567
891011121314
15161718192021
22232425262728

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Mar. 8th, 2026 02:26 am
Powered by Dreamwidth Studios