2015-09-29 18 views
6

üretir Ben çıktı abc3 görmezsiniz ancakHattı gizemli hata

File "f.ml", line 1, characters 46-47: 
Error: This function has type (unit, out_channel, unit) format -> unit 
     It is applied to too many arguments; maybe you forgot a `;'. 

eğlenceli parçası olduğunu ben değiştirirseniz 2+22 almak için bekliyoruz

let (a,p) = (2+2, Printf.printf) in p "abc"; p "%d" 3 ;; 

çalışır.

Kod neden olduğu gibi bir hata üretiyor, ancak +2 kaldırılmıyor mu?

+0

Ben de cevap ilgileniyorum, bu ilk bakışta garip. –

cevap

6

printf için OCaml'ın özel yazım hilesi ve değer polimorfizmi.

Bildiğiniz gibi, Printf.printf, string, ancak format veri tipini almaz. OCaml tipi denetleyicisi printf için dize hazır tiplendirilmesinde için özel bir kural vardır: Bağlam talep ederse bu format olarak yazıldığında ise:

# "%d";; 
- : string = "%d" 
# ("%d" : _format);; 
- : (int -> 'a, 'b, 'a) format = ... 

OCaml tür sistemi başka hüner denilen değer polimorfizm vardır (daha doğrusu, bu rahat değerdir polimorfizmi). Amacı, yan etkilerle doğru ifadeler yazmaktır. Ben ayrıntılarını açıklamak yok ama polimorfizm kısıtlar: kimlik işlevi fun x -> x sahipken, (fun x -> x) (fun x -> x) hiçbir polimorfik türü vardır, yukarıda ise

# fun x -> x;; 
- : 'a -> 'a = <fun> 
# (fun x -> x) (fun x -> x) 
- : '_a -> '_a = <fun> 

: polimorfik türleri içeremez "geniş" olarak adlandırılan ifadelerin bazı formları. Bu, (fun x -> x) (fun x -> x) ifadesinin şekli nedeniyle: "geniş". '_a garip tip değişkeni, monomorfik tip değişkendir: Bu, sadece bir kez bir türe örneklenebilir. Öte yandan, 'a gibi polimorfik değişkenler, her bir vue kullanımı için farklı bir tipte başlatılabilir.

en Kodunuzdaki geri dönelim: Burada

# let (a, p) = (2, Printf.printf);; 
val a : int 
val p : ('a, out_channel, unit) format -> 'a 

, p bir polimorfik tipi ('a, out_channel, unit) format -> 'a sahiptir. 'a, birden fazla türe göre başlatılabilir, bu nedenle p "abc"; p "%d" 3 yazılabilirdir: polimorfik tür, p ilk kullanımı için (unit, out_channel, unit) format -> unit ve p ikinci kullanımı için (int -> unit, out_channel, unit) format -> int -> unit olarak başlatılabilir.

Eğer geniş olan 2+2, sürekli 2, tüm ifadesinde çok geniş hale gelir değiştirmek ve sonra yazarak değişiklikleri:

İşte
# let (a, p) = (2+2, Printf.printf);; 
val a : int 
val p : ('_a, out_channel, unit) format -> '_a 

, p artık polimorfik değişkenleri 'a ama monomorfik '_a sahiptir. Bu monomorfik değişken, p'un ilk kullanımında unit'a birleştirilmiş (örneklendirilmiştir) ve sonuç olarak p 'un türü (unit, out_channel, unit) format -> unit olur. Sadece 1 argüman alabilir, bu yüzden 2 argüman ile p ikinci kullanımının yazılması başarısız olur.Bu durumdan kaçınmak için

kolay bir yolu ikiye sizin tanımını bölmek geçerli:

let a = 2 + 2 in 
let p = Printf.printf in 
p "abc"; p "%d" 3