செயற்கூறிய நிரலாக்கம் – தரவின வரையறை – பகுதி 9

இயல்நிலைமொழிகளில் (Static languages) ஒரு செயற்கூற்றின் வரையறையோடு, தரவினங்களும் (data types) பிணைக்கப்பட்டுள்ளதை, பின்வரும் எடுத்துக்காட்டில் காணலாம்.

public static String quote(String str) {
return "'" + str + "'";
}

பொதுப்படையான தரவினங்களைக் (generic types) குறிக்கும்போது, இது இன்னும் சிக்கலானதாகிறது.

private final Map<Integer, String> getPerson(Map<String, String> people, Integer personId) {
// ...
}

இயங்குநிலைமொழிகளில் (dynamic languages) இந்தச்சிக்கல் இருப்பதில்லை. ஜாவாஸ்கிரிப்ட்டிலேயே, நாம் பின்வருமாறு எளிதாக எழுதலாம்.

[code lang=”javascript”]
var getPerson = function(people, personId) {
// …
};
[/code]

தரவினங்களைப் பற்றி கவலைப்படாமல், எந்தவொரு தடங்கலுமில்லாமல், செயற்கூற்றின் வரையறையை நம்மால் படித்துப்புர்ந்துகொள்ளமுடிகிறது. இதிலுள்ள ஒரேயொரு சிக்கல் என்னவென்றால், ஒருவேளை, நாம் உள்ளீட்டு உருபுகளின் வரிசையை மாற்றிக்கொடுத்துவிட்டால், நிரலை இயக்கும்போது மட்டுமே, நம்மால் கண்டறியமுடியும். ஆனால், ஜாவா போன்ற இயல்நிலைமொழிகளில், இந்நிலை வராமல், நிரல்பெயர்ப்பி (compiler) பார்த்துக்கொள்கிறது.

இயல்நிலைமொழிகளின் வன்மையும், இயங்குநிலைமொழிகளின் எளிமையும் இருந்தால் இன்னும் நன்றாக இருக்குமே! அதற்கு வாய்ப்பிருக்கிறதா என நாம் யோசிக்கும்போது, அதற்கான விடையாக எல்ம் மொழி நமக்குக்கிடைக்கிறது.

[code lang=”ruby”]
add : Int -> Int -> Int
add x y =
x + y
[/code]

செயற்கூற்று வரையறைக்கு ஒருவரி முன்னதாக அதன் தரவினங்கள் குறிக்கப்படுகின்றன. இந்த ஒருவரி மாற்றம், மிகப்பெரிய வித்தியாசங்களுக்கு வித்திடுகிறது.

இங்கே, தரவினங்களின் வரையறையைப் படிக்கும்போது அதில் ஏதோ எழுத்துப்பிழை இருப்பதைப்போல உணரலாம். முதலாவது அம்புக்குறிக்குப்பதிலாக, காற்புள்ளி இருந்திருக்கவேண்டுமல்லவா?! ஆனால், இவ்வரையறையில் பிழையேதுமில்லை. இதைப்புரிந்துகொள்ள, அடைப்புக்குறிகளைப் பயன்படுத்தலாம்.

[code lang=”ruby”]
add : Int -> (Int -> Int)
[/code]

add என்பது, ஒரு Int தரவினத்தை உள்ளீடாக ஏற்றுக்கொண்டு, ஒரு செயற்கூற்றைத் தருகிறது. இச்செயற்கூறு, ஒரு Int தரவினத்தை உள்ளீடாக ஏற்றுக்கொண்டு, மற்றொரு Intஐத் தருகிறது.

அடைப்புக்குறிகளோடு விளக்கப்பட்ட மற்றொரு எடுத்துக்காட்டைப் பார்க்கலாம்:

[code lang=”ruby”]
doSomething : String -> (Int -> (String -> String))
doSomething prefix value suffix =
prefix ++ (toString value) ++ suffix
[/code]

      இங்கே doSomething என்பது String தரவினத்தை ஏற்றுக்கொண்டு, ஒரு செயற்கூற்றைத்தருகிறது.
      இச்செயற்கூறு, Int தரவினத்தை ஏற்றுக்கொண்டு, ஒரு செயற்கூற்றைத்தருகிறது.
      இச்செயற்கூறு, String தரவினத்தை ஏற்றுக்கொண்டு, மற்றொரு String ஐத்தருகிறது.

இங்கே, ஒவ்வொரு செயற்கூறும், ஒரேயொரு உள்ளீட்டு உருபைமட்டுமே ஏற்கிறது என்பதைக் கவனிக்கவேண்டும். ஏனென்றால், நாம் ஏற்கனவே படித்ததுபோல எல்ம் மொழியில் எல்லா செயற்கூறுகளும் ஒற்றைஉள்ளீட்டாக்கத்திற்கு உட்பட்டவை. இத்தரவினங்களின் வரையறை, இட்மிருந்து வலமாகச்செல்வதால், அடைப்புக்குறிகளை இடவேண்டிய அவசியமில்லை. எனவே, மேற்கண்ட தரவின வரையறையை, பின்வருமாறு எளிமையாகவும் எழுதலாம்.

[code lang=”ruby”]
doSomething : String -> Int -> String -> String
[/code]

ஒரு செயற்கூற்றுக்கு, மற்றொரு செயற்கூற்றை உள்ளீடாக அனுப்பும்போது அடைப்புக்குறிகள் அவசியமாகின்றன. அவையில்லாமல், குழப்பம் ஏற்பட வாய்ப்புள்ளது. எ.கா:

[code lang=”ruby”]
takes2Params : Int -> Int -> String
takes2Params num1 num2 =
— do something
[/code]

மேற்கண்ட வரையறை, பின்வரும் வரையறையிலிருந்து முற்றிலும் மாறுபட்டது.

[code lang=”ruby”]
takes1Param : (Int -> Int) -> String
takes1Param f =
— do something
[/code]

இங்கே, takes2Params என்ற செயற்கூறு, இரண்டு Int தரவினங்களை உள்ளீடாக ஏற்கிறது. ஆனால், takes1Param என்ற செயற்கூறு, ஒரு Intஐ உள்ளீடாக ஏற்று மற்றொரு Intஐத்தரவல்லதொரு செயற்கூற்றை உள்ளீடாக ஏற்றுக்கொண்டு, இறுதியாக ஒரு String ஐ வெளியிடுகிறது.

பொதுப்படையான செயற்கூறுகளின் தரவின வரையறையை, இப்போது காணலாம். எடுத்துக்காட்டாக, mapஐ எடுத்துக்கொள்ளலாம்.

[code lang=”ruby”]
map : (a -> b) -> List a -> List b
map f list =
// …
[/code]

செயற்கூறிய செயற்கூறுகள் பகுதியில் கண்டதுபோல, ஒரு பட்டியலிலிருந்து, மற்றொரு பட்டியலை map உருவாக்குகிறது. அதாவது, a என்ற தரவினத்தை, b ஆகமாற்றக்கூடிய செயற்கூற்றையும், a தரவினங்கள் கொண்ட பட்டியலையும் உள்ளீடாக எடுத்துக்கொண்டு, b தரவினங்கள்கொண்ட பட்டியலை வெளியிடுகிறது.

இங்கே, a, b ஆகியன எந்தவொரு தரவினத்திற்கும் பொருந்தக்கூடியவை. ஒருகுறிப்பிட்ட தரவினத்தைக்குறிப்பிட வேண்டிமெனில், அதன் முதலெழுத்து பெரிய எழுத்தாக இருக்கவேண்டும் (String, Int என்பனபோல)

(a -> a) என்ற வரையறையைக் கண்டால், அச்செயற்கூற்றின் உள்ளீட்டு உருபும், வெளியீடும் ஒரே தரவினமாக இருக்கவேண்டும்.

மாறாக, (a -> b) என்ற வரையறையில், aம், bம் ஒரே தரவினமாகவும் இருக்கலாம், அல்லது வெவ்வேறு தரவினமாகவும் இருக்கலாம். ஜாவா, C# போன்றமொழிகளிலும் இதுபோன்ற சித்தாந்தங்கள், generics என்ற பெயரில் உங்களுக்கு பரிச்சயமானவையாக இருக்கலாம்.

[code lang=”ruby”]
map : (a -> b) -> List a -> List b
map : (Int -> String) -> List Int -> List String
[/code]

மூலம்: Charles Scalfani எழுதிய கட்டுரைத்தொடரின் தமிழாக்கம். அவரது அனுமதியோடு மொழிபெயர்க்கப்பட்டுள்ளது.

%d bloggers like this: