Otomatik Genelleştirme

F# işlev ve ifade türlerini değerlendirmek için tür çıkarımı kullanır. Bu konu başlığında F# işlevinin bağımsız değişkenleri ve işlev türlerini otomatik olarak genelleştirerek mümkün olduğunda birden çok türle nasıl çalıştığı açıklanmaktadır.

Otomatik Genelleştirme

F# derleyicisi, bir işlev üzerinde tür çıkarımı gerçekleştirdiğinde, belirli bir parametrenin genel olup olmadığını belirler. Derleyici her parametreyi inceler ve işlevin bu parametrenin belirli türüne bağımlılığı olup olmadığını belirler. Aksi takdirde, tür genel olarak çıkarılır.

Aşağıdaki kod örneği, derleyicinin genel olarak çıkaracağı bir işlevi gösterir.

let max a b = if a > b then a else b

türü olarak çıkarılır 'a -> 'a -> 'a.

türü, bunun aynı bilinmeyen türde iki bağımsız değişken alan ve aynı türde bir değer döndüren bir işlev olduğunu gösterir. Önceki işlevin genel olmasının nedenlerinden biri, büyüktür işlecinin (>) kendisinin genel olmasıdır. büyüktür işlecinin imzası 'a -> 'a -> boolvardır. Tüm işleçler genel değildir ve bir işlevdeki kod genel olmayan bir işlev veya işleçle birlikte bir parametre türü kullanıyorsa, bu parametre türü genelleştirilemez.

Genel max olduğundan, aşağıdaki örneklerde gösterildiği gibi int, floatve benzeri türlerle kullanılabilir.

let biggestFloat = max 2.0 3.0
let biggestInt = max 2 3

Ancak, iki bağımsız değişken aynı türde olmalıdır. İmza, değil 'a -> 'b -> 'aşeklindedir'a -> 'a -> 'a. Bu nedenle, türler eşleşmediğinden aşağıdaki kod bir hata oluşturur.

// Error: type mismatch.
let biggestIntFloat = max 2.0 3

işlevi, max büyüktür işlecini destekleyen herhangi bir türle de çalışır. Bu nedenle, aşağıdaki kodda gösterildiği gibi bir dizede de kullanabilirsiniz.

let testString = max "cab" "cat"

Değer Kısıtlaması

Derleyici, otomatik genelleştirmeyi yalnızca açık bağımsız değişkenleri olan tam işlev tanımlarında ve basit sabit değerlerde gerçekleştirir.

Bu, belirli bir tür için yeterince kısıtlanmamış ancak aynı zamanda genelleştirilebilir olmayan bir kod derlemeye çalışırsanız derleyicinin bir hata oluşturacağı anlamına gelir. Bu sorunun hata iletisi, değer kısıtlaması olarak değerler için otomatik genelleştirmeye yönelik bu kısıtlamayı ifade eder.

Genellikle değer kısıtlama hatası, bir yapının genel olmasını istediğinizde ancak derleyicinin bunu genelleştirmek için yeterli bilgiye sahip olmaması durumunda ya da istemeden bir yapıda yeterli tür bilgilerini atladığınızda oluşur. Değer kısıtlama hatasının çözümü, tür çıkarımı sorununu aşağıdaki yollardan biriyle tamamen kısıtlamak için daha açık bilgiler sağlamaktır:

  • Bir değere veya parametreye açık tür ek açıklaması ekleyerek türün genel olmayan olmasını kısıtlar.

  • Sorun, işlev bileşimi veya tamamlanmamış curried işlev bağımsız değişkenleri gibi genel bir işlev tanımlamak için genel olarak oluşturulamayan bir yapı kullanıyorsa, işlevi sıradan bir işlev tanımı olarak yeniden yazmayı deneyin.

  • Sorun genelleştirilemeyecek kadar karmaşık bir ifadeyse, fazladan, kullanılmayan bir parametre ekleyerek bunu bir işlev haline getirin.

  • Açık genel tür parametreleri ekleyin. Bu seçenek nadiren kullanılır.

Aşağıdaki kod örnekleri bu senaryoların her birini göstermektedir.

1. Olay: İfade çok karmaşık. Bu örnekte, listenin counter olması int option refamaçlanmıştır, ancak basit bir sabit değer olarak tanımlanmamıştır.

let counter = ref None
// Adding a type annotation fixes the problem:
let counter : int option ref = ref None

Olay 2: Genel bir işlev tanımlamak için genelleştirilebilir olmayan bir yapı kullanma. Bu örnekte yapı, işlev bağımsız değişkenlerinin kısmi uygulamasını içerdiğinden genelleştirilebilir değildir.

let maxhash = max << hash
// The following is acceptable because the argument for maxhash is explicit:
let maxhash obj = (max << hash) obj

Olay 3: Ek, kullanılmayan bir parametre ekleme. Bu ifade genelleştirme için yeterince basit olmadığından, derleyici değer kısıtlama hatasını verir.

let emptyList10 = Array.create 10 []
// Adding an extra (unused) parameter makes it a function, which is generalizable.
let emptyList10 () = Array.create 10 []

Olay 4: Tür parametreleri ekleniyor.

let arrayOf10Lists = Array.create 10 []
// Adding a type parameter and type annotation lets you write a generic value.
let arrayOf10Lists<'T> = Array.create 10 ([]:'T list)

Son örnekte değer, aşağıdaki gibi birçok farklı türde değer oluşturmak için kullanılabilecek bir tür işlevine dönüşür:

let intLists = arrayOf10Lists<int>
let floatLists = arrayOf10Lists<float>

Ayrıca bkz.