ক্রিয়ামূলক ভাষায় 'প্যাটার্ন ম্যাচিং' কী?


127

আমি ফাংশনাল প্রোগ্রামিং সম্পর্কে পড়ছি এবং আমি লক্ষ্য করেছি যে প্যাটার্ন ম্যাচিংকে অনেকগুলি নিবন্ধে কার্যকরী ভাষার অন্যতম প্রধান বৈশিষ্ট্য হিসাবে উল্লেখ করা হয়েছে।

কেউ জাভা / সি ++ / জাভাস্ক্রিপ্ট বিকাশকারী এর অর্থ কী বোঝাতে পারে?


উত্তর:


141

প্যাটার্ন মিলটি বোঝার জন্য তিনটি অংশ ব্যাখ্যা করা দরকার:

  1. বীজগণিত তথ্য প্রকার।
  2. কী প্যাটার্ন মিলছে
  3. কেন এটা দুর্দান্ত।

সংক্ষেপে বীজগণিত ডেটা টাইপ

এমএল-এর মতো কার্যকরী ভাষা আপনাকে "ডিসজেইন্ট ইউনিয়ন" বা "বীজগণিত তথ্য প্রকার" নামক সাধারণ ডেটা সংজ্ঞায়িত করতে দেয়। এই ডেটা স্ট্রাকচারগুলি সাধারণ পাত্রে, এবং পুনরাবৃত্তভাবে সংজ্ঞায়িত করা যায়। উদাহরণ স্বরূপ:

type 'a list =
    | Nil
    | Cons of 'a * 'a list

স্ট্যাকের মতো ডেটা কাঠামো সংজ্ঞায়িত করে। এটিকে এই সি # এর সমতুল্য মনে করুন:

public abstract class List<T>
{
    public class Nil : List<T> { }
    public class Cons : List<T>
    {
        public readonly T Item1;
        public readonly List<T> Item2;
        public Cons(T item1, List<T> item2)
        {
            this.Item1 = item1;
            this.Item2 = item2;
        }
    }
}

সুতরাং, Consএবং Nilসনাক্তকারীরা সাধারণ একটি সাধারণ শ্রেণি of x * y * z * ...সংজ্ঞায়িত করে , যেখানে নির্মাতা এবং কিছু ডেটা ধরণের সংজ্ঞা দেয়। কনস্ট্রাক্টরের প্যারামিটারগুলি নামহীন, তারা অবস্থান এবং ডেটা ধরণের দ্বারা সনাক্ত করা হয়।

আপনি আপনার a listশ্রেণীর উদাহরণগুলি তৈরি করেন:

let x = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))

যা একই:

Stack<int> x = new Cons(1, new Cons(2, new Cons(3, new Cons(4, new Nil()))));

সংক্ষেপে প্যাটার্ন মিলছে

প্যাটার্ন ম্যাচিং এক ধরণের টাইপ-টেস্টিং। সুতরাং আসুন আমরা ধরে নিই যে আমরা উপরের মতো একটি স্ট্যাক অবজেক্ট তৈরি করেছি, আমরা স্ট্যাকটি উঁকি দেওয়ার এবং পপ করার পদ্ধতিগুলি নিম্নলিখিতভাবে প্রয়োগ করতে পারি:

let peek s =
    match s with
    | Cons(hd, tl) -> hd
    | Nil -> failwith "Empty stack"

let pop s =
    match s with
    | Cons(hd, tl) -> tl
    | Nil -> failwith "Empty stack"

উপরের পদ্ধতিগুলি নীচের সি # এর সমতুল্য (যদিও এর মতো প্রয়োগ করা হয়নি):

public static T Peek<T>(Stack<T> s)
{
    if (s is Stack<T>.Cons)
    {
        T hd = ((Stack<T>.Cons)s).Item1;
        Stack<T> tl = ((Stack<T>.Cons)s).Item2;
        return hd;
    }
    else if (s is Stack<T>.Nil)
        throw new Exception("Empty stack");
    else
        throw new MatchFailureException();
}

public static Stack<T> Pop<T>(Stack<T> s)
{
    if (s is Stack<T>.Cons)
    {
        T hd = ((Stack<T>.Cons)s).Item1;
        Stack<T> tl = ((Stack<T>.Cons)s).Item2;
        return tl;
    }
    else if (s is Stack<T>.Nil)
        throw new Exception("Empty stack");
    else
        throw new MatchFailureException();
}

(প্রায় সর্বদা, এমএল ভাষাগুলি রান-টাইম টাইপ-টেস্ট বা ক্যাসেটগুলি ছাড়াই প্যাটার্ন মেলানো বাস্তবায়ন করে, তাই সি # কোডটি কিছুটা বিভ্রান্তিকর Let's

সংক্ষেপে ডেটা স্ট্রাকচার পচে যাওয়া

ঠিক আছে, ফিরে যাওয়া যাক পদ্ধতিতে ফিরে যান:

let peek s =
    match s with
    | Cons(hd, tl) -> hd
    | Nil -> failwith "Empty stack"

কৌশলটি বোঝা যাচ্ছে যে hdএবং tlসনাক্তকারীরা পরিবর্তনশীল (ভুল) ... যেহেতু তারা পরিবর্তনযোগ্য নয়, তারা আসলে "পরিবর্তনশীল" নয়, "মানগুলি";))) যদি sটাইপ হয়েছে Cons, তাহলে আমরা কন্সট্রাকটর বাইরে তার মান বৈঠাচালনা আউট করতে যাচ্ছেন এবং বাঁধুন তাদের নামে ভেরিয়েবল hdএবং tl

কারণ এটা আমাদের তার দ্বারা একটি ডাটা স্ট্রাকচার পচা দেয় প্যাটার্ন ম্যাচিং দরকারী আকৃতি পরিবর্তে তার বিষয়বস্তু । সুতরাং কল্পনা করুন যে আমরা যদি বাইনারি গাছটিকে নীচে নির্ধারণ করি:

type 'a tree =
    | Node of 'a tree * 'a * 'a tree
    | Nil

আমরা কিছু গাছের আবর্তন নিম্নরূপ হিসাবে সংজ্ঞায়িত করতে পারি :

let rotateLeft = function
    | Node(a, p, Node(b, q, c)) -> Node(Node(a, p, b), q, c)
    | x -> x

let rotateRight = function
    | Node(Node(a, p, b), q, c) -> Node(a, p, Node(b, q, c))
    | x -> x

( let rotateRight = functionকনস্ট্রাক্টর সিনট্যাক্স চিনির জন্য let rotateRight s = match s with ...।)

সুতরাং ভেরিয়েবলের সাথে ডেটা স্ট্রাকচারকে বাঁধাই করা ছাড়াও আমরা এটিতেও ড্রিল করতে পারি। ধরা যাক আমাদের একটি নোড আছে let x = Node(Nil, 1, Nil)। আমরা যদি কল করি rotateLeft x, আমরা xপ্রথম প্যাটার্নের বিরুদ্ধে পরীক্ষা করি , যা মিলতে ব্যর্থ হয় কারণ ডান সন্তানের Nilপরিবর্তে টাইপ থাকে Node। এটি পরবর্তী প্যাটার্নে চলে যাবে x -> x, যা কোনও ইনপুটের সাথে মিলবে এবং এটিকে অশোধিত ফিরিয়ে দেবে।

তুলনার জন্য, আমরা উপরের পদ্ধতিগুলি সি # তে লিখব:

public abstract class Tree<T>
{
    public abstract U Match<U>(Func<U> nilFunc, Func<Tree<T>, T, Tree<T>, U> nodeFunc);

    public class Nil : Tree<T>
    {
        public override U Match<U>(Func<U> nilFunc, Func<Tree<T>, T, Tree<T>, U> nodeFunc)
        {
            return nilFunc();
        }
    }

    public class Node : Tree<T>
    {
        readonly Tree<T> Left;
        readonly T Value;
        readonly Tree<T> Right;

        public Node(Tree<T> left, T value, Tree<T> right)
        {
            this.Left = left;
            this.Value = value;
            this.Right = right;
        }

        public override U Match<U>(Func<U> nilFunc, Func<Tree<T>, T, Tree<T>, U> nodeFunc)
        {
            return nodeFunc(Left, Value, Right);
        }
    }

    public static Tree<T> RotateLeft(Tree<T> t)
    {
        return t.Match(
            () => t,
            (l, x, r) => r.Match(
                () => t,
                (rl, rx, rr) => new Node(new Node(l, x, rl), rx, rr))));
    }

    public static Tree<T> RotateRight(Tree<T> t)
    {
        return t.Match(
            () => t,
            (l, x, r) => l.Match(
                () => t,
                (ll, lx, lr) => new Node(ll, lx, new Node(lr, x, r))));
    }
}

গুরুত্ব সহকারে।

প্যাটার্নের মিলটি দুর্দান্ত

আপনি দর্শনার্থী প্যাটার্নটি ব্যবহার করে সি # তে প্যাটার্ন মিলের অনুরূপ কিছু বাস্তবায়ন করতে পারেন তবে এটি প্রায় তত নমনীয় নয় কারণ আপনি জটিল ডেটা কাঠামো কার্যকরভাবে পচিয়ে দিতে পারবেন না। তদুপরি, আপনি যদি প্যাটার্ন ম্যাচিং ব্যবহার করছেন তবে সংকলক আপনাকে বলবে যে আপনি কোনও মামলা রেখে গেছেন কিনা । এটা কি দুর্দান্ত?

আপনি কীভাবে প্যাটার্ন মিল না করে সি # বা ভাষায় অনুরূপ কার্যকারিতাটি প্রয়োগ করবেন তা চিন্তা করুন। রানটাইমে আপনি পরীক্ষা-পরীক্ষা এবং ক্যাসেট ছাড়াই কীভাবে এটি করবেন তা ভেবে দেখুন। এটি অবশ্যই কঠিন নয় , কেবল জটিল এবং বিশাল। আপনি প্রতিটি কেস কেয়ার করেছেন তা নিশ্চিত করার জন্য আপনার কাছে সংকলক চেকিং নেই।

সুতরাং প্যাটার্ন মিলটি আপনাকে খুব সুবিধাজনক, কমপ্যাক্ট সিনট্যাক্সে ডেটা স্ট্রাকচারগুলি পচিয়ে ও নেভিগেট করতে সহায়তা করে, এটি কমপক্ষে কিছুটা হলেও আপনার কোডের লজিক পরীক্ষা করতে সংকলকটিকে সক্ষম করে । এটা সত্যিই হয় একটি হত্যাকারী বৈশিষ্ট্য।


+1 তবে ম্যাথমেটিকার মতো প্যাটার্ন মেলানো সহ অন্যান্য ভাষা সম্পর্কে ভুলবেন না।
জেডি

1
ভেরিয়েবল ", কিন্তু" মান "errm ... যেহেতু তারা অপরিবর্তনীয় আছেন, তারা সত্যিই না হন" ";)" তারা হয় ভেরিয়েবল; এটি বিবিধ পরিবর্তনযোগ্য যে এটি ভুল লেবেলযুক্ত । তবুও, দুর্দান্ত উত্তর!
ডোভাল

3
"প্রায় সর্বদা, এমএল ভাষা রান-টাইম টাইপ-টেস্ট বা ক্যাসেটগুলি ছাড়াই প্যাটার্ন ম্যাচিং প্রয়োগ করে" <- এটি কীভাবে কাজ করে? আপনি আমাকে একটি প্রাইমারের দিকে নির্দেশ করতে পারেন?
ডেভিড মোলস

1
@ ডেভিডমোলস: টাইপ সিস্টেমটি প্যাটার্ন ম্যাচগুলি সম্পূর্ণরূপে এবং অপ্রয়োজনীয় নয় বলে প্রমাণ করে সমস্ত রান-টাইম চেকগুলি এলিডে সম্ভব করে তোলে। আপনি যদি এসএমএল, ওসিএএমএল বা এফ # এর মতো কোনও ভাষা খাওয়ানোর চেষ্টা করেন তবে এটি সম্পূর্ণরূপে নয় বা অপ্রয়োজনীয় থাকে তবে সংকলক আপনাকে সংকলনের সময় সতর্ক করবে। এটি একটি অত্যন্ত শক্তিশালী বৈশিষ্ট্য কারণ এটি আপনাকে আপনার কোডটি পুনরায় সাজিয়ে রান-টাইম চেকগুলি অপসারণ করতে দেয়, অর্থাত আপনার কোডের দিকগুলি সঠিক প্রমাণিত হতে পারে। তদতিরিক্ত, এটি বোঝা সহজ!
জেডি

@ জনহরপ আমি দেখতে পাচ্ছি যে এটি কীভাবে কাজ করবে (কার্যকরভাবে এটি ডায়নামিক মেসেজ প্রেরণের অনুরূপ) তবে রান টাইমে আপনি কোনও ধরনের পরীক্ষা ছাড়াই কিভাবে একটি শাখা নির্বাচন করবেন তা আমি দেখতে পাচ্ছি না।
ডেভিড মোলস

33

সংক্ষিপ্ত উত্তর: প্যাটার্নের মিলটি উত্থাপিত হয় কারণ কার্যকরী ভাষা সমান চিহ্নকে অ্যাসাইনমেন্টের পরিবর্তে সমতুল্যতা হিসাবে বিবেচনা করে ।

দীর্ঘ উত্তর: প্যাটার্ন মিলটি দেওয়া মানটির "আকৃতি" এর উপর ভিত্তি করে প্রেরণের একটি ফর্ম। কার্যকরী ভাষায়, আপনি যে ডেটাটাইপগুলি সংজ্ঞায়িত করেন তা হ'ল সাধারণত বৈষম্যমূলক ইউনিয়ন বা বীজগণিত ডেটা ধরণের হিসাবে পরিচিত। উদাহরণস্বরূপ, একটি (সংযুক্ত) তালিকা কি? একটি লিঙ্ক তালিকা Listকিছু টাইপ এর কিছু aপারেন খালি তালিকা Nilবা টাইপ কিছু উপাদান a Consএকটি সম্মুখের ইডি List a(একটি তালিকা aগুলি)। হাস্কেলে (কার্যকরী ভাষা যার সাথে আমি সবচেয়ে বেশি পরিচিত), আমরা এটি লিখি

data List a = Nil
            | Cons a (List a)

সমস্ত বৈষম্যমূলক ইউনিয়নগুলি এইভাবে সংজ্ঞায়িত করা হয়: একটি একক প্রকারের এটি তৈরির জন্য বিভিন্ন উপায়ে একটি নির্দিষ্ট সংখ্যা রয়েছে; নির্মাতাদের, যেমন Nilএবং Consএখানে, কনস্ট্রাক্টর বলা হয়। এর অর্থ হ'ল এই ধরণের মান List aদুটি পৃথক নির্মাতা দ্বারা তৈরি করা যেতে পারে - এটিতে দুটি পৃথক আকার থাকতে পারে। সুতরাং ধরুন আমরা headতালিকার প্রথম উপাদানটি পেতে একটি ফাংশন লিখতে চাই । হাস্কেল-এ, আমরা এটি লিখব

-- `head` is a function from a `List a` to an `a`.
head :: List a -> a
-- An empty list has no first item, so we raise an error.
head Nil        = error "empty list"
-- If we are given a `Cons`, we only want the first part; that's the list's head.
head (Cons h _) = h

যেহেতু List aমান দুটি ভিন্ন ধরণের হতে পারে, তাই আমাদের প্রতিটি পৃথকভাবে পরিচালনা করতে হবে; এটি প্যাটার্ন মিলছে। ইন head x, যদি xপ্যাটার্নটির সাথে মেলে Nil, তবে আমরা প্রথম কেসটি চালাই; যদি এটি প্যাটার্নটির সাথে মেলে তবে Cons h _আমরা দ্বিতীয়টি চালাই।

সংক্ষিপ্ত উত্তর, ব্যাখ্যা করা হয়েছে: আমি মনে করি এই আচরণ সম্পর্কে ভাবার সেরা উপায়গুলির মধ্যে একটি হল সমান চিহ্ন সম্পর্কে আপনি কীভাবে চিন্তা করেন তা পরিবর্তন করে। কার্লি-ব্র্যাকেট ভাষায় এবং বৃহত্তর, =অ্যাসাইনমেন্ট নির্দেশ করে: এর a = bঅর্থ "মেক aইন b"। প্রচুর কার্যকরী ভাষায়, =সাম্যের দৃser়তা বোঝায়: let Cons a (Cons b Nil) = frob x জোর দেয় যে বাম দিকের Cons a (Cons b Nil)জিনিসটি ডানদিকের জিনিসটির সমান frob x; এছাড়াও, বামে ব্যবহৃত সমস্ত ভেরিয়েবল দৃশ্যমান হয়ে যায়। এটি ফাংশন আর্গুমেন্টগুলির সাথে কী ঘটছে: আমরা দৃ as়ভাবে জানিয়েছি যে প্রথম যুক্তিটি দেখতে ভাল লাগে Nil, এবং যদি তা না হয় তবে আমরা চেক করেই থাকি।


সমান চিহ্ন সম্পর্কে চিন্তা করার কী আকর্ষণীয় উপায়। ভাগ করে নেওয়ার জন্য ধন্যবাদ!
জড়হালি

2
কী Consমানে?
রায়মসনসন

2
@Roymunson: Consহয় কনস tructor করে একটি মাথা থেকে বের একটি (লিঙ্ক) তালিকা তৈরী করে ( a) এবং একটি লেজ ( List a)। নামটি এসেছে লিস্প থেকে। হাস্কেলের মধ্যে অন্তর্নির্মিত তালিকার ধরণের জন্য এটি :অপারেটর (যা এখনও "কনস" হিসাবে উচ্চারণ করা হয়)।
আন্টাল স্পেক্টর-জাবুসকি

23

এর অর্থ লেখার পরিবর্তে

double f(int x, int y) {
  if (y == 0) {
    if (x == 0)
      return NaN;
    else if (x > 0)
      return Infinity;
    else
      return -Infinity;
  } else
     return (double)x / y;
}

তুমি লিখতে পারো

f(0, 0) = NaN;
f(x, 0) | x > 0 = Infinity;
        | else  = -Infinity;
f(x, y) = (double)x / y;

আরে, সি ++ প্যাটার্ন মেলানোও সমর্থন করে।

static const int PositiveInfinity = -1;
static const int NegativeInfinity = -2;
static const int NaN = -3;

template <int x, int y> struct Divide {
  enum { value = x / y };
};
template <bool x_gt_0> struct aux { enum { value = PositiveInfinity }; };
template <> struct aux<false> { enum { value = NegativeInfinity }; };
template <int x> struct Divide<x, 0> {
  enum { value = aux<(x>0)>::value };
};
template <> struct Divide<0, 0> {
  enum { value = NaN };
};

#include <cstdio>

int main () {
    printf("%d %d %d %d\n", Divide<7,2>::value, Divide<1,0>::value, Divide<0,0>::value, Divide<-1,0>::value);
    return 0;
};

1
স্কেলে: ডাবল আমদানি করুন _ (x, y) => x / y}}
ফ্রাঙ্কা

12

প্যাটার্ন মিলটি হ'ল স্টেরয়েডগুলিতে ওভারলোড হওয়া পদ্ধতির মতো। সবচেয়ে সহজ কেসটি আপনি জাভাতে যা দেখেছেন তার প্রায় একই রকম হবে, যুক্তিগুলি নামের সাথে তালিকার একটি তালিকা। কল করার জন্য সঠিক পদ্ধতিটি পাস হওয়া আর্গুমেন্টগুলির উপর ভিত্তি করে এবং এটি প্যারামিটার নামের সাথে এই যুক্তিগুলির একটি অ্যাসাইনমেন্ট হিসাবে দ্বিগুণ।

প্যাটার্নগুলি কেবল আরও এক ধাপ এগিয়ে যায় এবং আরও পরে পাস হওয়া আর্গুমেন্টগুলি গঠন করতে পারে। এটি যুক্তির মানের উপর ভিত্তি করে প্রকৃতপক্ষে ম্যাচ করতে গার্ডগুলিও ব্যবহার করতে পারে। প্রদর্শনের জন্য, আমি জাভাস্ক্রিপ্টের মতো প্যাটার্ন মেলানোর মতো ভান করলাম।

function foo(a,b,c){} //no pattern matching, just a list of arguments

function foo2([a],{prop1:d,prop2:e}, 35){} //invented pattern matching in JavaScript

Foo2 এ এটি একটি অ্যারে হিসাবে প্রত্যাশা করে, এটি দ্বিতীয় যুক্তিটি পৃথক করে, দুটি প্রপস (প্রোপ 1, প্রোপ 2) দিয়ে কোনও বস্তুর প্রত্যাশা করে এবং d এবং e এর বৈশিষ্ট্যগুলির মানগুলি নির্ধারণ করে এবং তৃতীয় আর্গুমেন্টটি প্রত্যাশা করে 35।

জাভাস্ক্রিপ্ট থেকে পৃথক, প্যাটার্ন মেলানো ভাষা সাধারণত একই নামের সাথে একাধিক ফাংশন মঞ্জুর করে, তবে বিভিন্ন নিদর্শন। এইভাবে এটি পদ্ধতি ওভারলোডিংয়ের মতো। আমি ইরং এ উদাহরণ দিচ্ছি:

fibo(0) -> 0 ;
fibo(1) -> 1 ;
fibo(N) when N > 0 -> fibo(N-1) + fibo(N-2) .

আপনার চোখকে কিছুটা ঝাপসা করুন এবং আপনি এটি জাভাস্ক্রিপ্টে কল্পনা করতে পারেন। এরকম কিছু হতে পারে:

function fibo(0){return 0;}
function fibo(1){return 1;}
function fibo(N) when N > 0 {return fibo(N-1) + fibo(N-2);}

পয়েন্টটি হ'ল আপনি যখন ফাইবোকে কল করবেন তখন প্রয়োগটি প্রয়োগ করে এটি আর্গুমেন্টের উপর ভিত্তি করে, তবে যেখানে জাভা ওভারলোডিংয়ের একমাত্র মাধ্যম হিসাবে সীমাবদ্ধ থাকে সেখানে প্যাটার্ন মেলানো আরও বেশি কিছু করতে পারে।

এখানে দেখানো হিসাবে ফাংশন ওভারলোডিং এর বাইরে একই নীতিটি অন্য জায়গাগুলিতে প্রয়োগ করা যেতে পারে যেমন কেস স্টেটমেন্ট বা ডিস্ট্রাকচারিং অ্যাসিটিংমেন্ট। জাভাস্ক্রিপ্ট এমনকি এটি 1.7 আছে


8

প্যাটার্ন ম্যাচিং আপনাকে কোডের একটি শাখা নির্বাচন করতে কিছু নিদর্শনগুলির সাথে মান (বা কোনও অবজেক্ট) মেলাতে দেয়। সি ++ দৃষ্টিকোণ থেকে এটি switchবিবৃতিটির সাথে কিছুটা মিলে যেতে পারে । ক্রিয়ামূলক ভাষায়, প্যাটার্ন মিলটি মান হিসাবে আদিম মানের যেমন পূর্ণসংখ্যার সাথে মিলের জন্য ব্যবহার করা যেতে পারে। তবে এটি রচনাধর্মী ধরণের জন্য আরও কার্যকর।

প্রথমে আসুন আদিম মানগুলিতে (বর্ধিত সিউডো-সি ++ ব্যবহার করে switch) প্যাটার্নের মিলটি প্রদর্শন করব :

switch(num) {
  case 1: 
    // runs this when num == 1
  case n when n > 10: 
    // runs this when num > 10
  case _: 
    // runs this for all other cases (underscore means 'match all')
}

দ্বিতীয় ব্যবহারে ফাংশনাল ডেটা টাইপ যেমন টিউপলস (যা আপনাকে একক মানে একাধিক বস্তু সংরক্ষণের অনুমতি দেয়) এবং বৈষম্যমূলক ইউনিয়নগুলির সাথে ডিল করে যা আপনাকে এমন একটি বিকল্প তৈরি করতে দেয় যা বেশ কয়েকটি বিকল্পের মধ্যে একটি থাকতে পারে। এটি enumপ্রতিটি লেবেলের কিছু মানও বহন করতে পারে এটিকে কিছুটা মনে হচ্ছে। সিউডো-সি ++ সিনট্যাক্সে:

enum Shape { 
  Rectangle of { int left, int top, int width, int height }
  Circle of { int x, int y, int radius }
}

প্রকারের Shapeমানতে এখন Rectangleসমস্ত স্থানাঙ্কের সাথে বা একটি Circleকেন্দ্র এবং ব্যাসার্ধের সমন্বয়ে থাকতে পারে । প্যাটার্ন মিলটি Shapeপ্রকারের সাথে কাজ করার জন্য আপনাকে একটি ফাংশন লিখতে দেয় :

switch(shape) { 
  case Rectangle(l, t, w, h): 
    // declares variables l, t, w, h and assigns properties
    // of the rectangle value to the new variables
  case Circle(x, y, r):
    // this branch is run for circles (properties are assigned to variables)
}

অবশেষে, আপনি নেস্টেড নিদর্শনগুলিও ব্যবহার করতে পারেন যা উভয় বৈশিষ্ট্যকে একত্রিত করে। উদাহরণস্বরূপ, আপনি Circle(0, 0, radius)যে বিন্দুতে [0, 0] এর কেন্দ্রে রয়েছেন এবং কোনও ব্যাসার্ধ রয়েছে তার সমস্ত আকারের সাথে মিলে যেতে ব্যবহার করতে পারেন (ব্যাসার্ধের মানটি নতুন ভেরিয়েবলের জন্য নির্ধারিত হবে radius)।

এটি সি ++ দৃষ্টিকোণ থেকে কিছুটা অপরিচিত মনে হতে পারে তবে আমি আশা করি যে আমার সিউডো-সি ++ ব্যাখ্যাটি পরিষ্কার করে দেবে। ক্রিয়ামূলক প্রোগ্রামিং বেশ ভিন্ন ধারণার উপর ভিত্তি করে, তাই এটি কার্যকরী ভাষায় আরও ভাল বোঝায়!


5

প্যাটার্ন ম্যাচিং যেখানে আপনার ভাষার জন্য দোভাষী আপনার দেওয়া আর্গুমেন্টের কাঠামো এবং সামগ্রীর উপর ভিত্তি করে একটি নির্দিষ্ট ফাংশন চয়ন করবে।

এটি কেবলমাত্র একটি কার্যকরী ভাষার বৈশিষ্ট্যই নয়, বহু বিভিন্ন ভাষার জন্য উপলভ্য।

আমি যখন প্রথমবারের মত ধারণাটি পেলাম তখন যখন আমি প্রোলগ শিখি তখন এটি ভাষার মূল স্থান যেখানে ছিল।

যেমন

সর্বশেষ ([লাস্ট আইটেম], লাস্ট আইটেম)।

সর্বশেষ ([প্রধান | লেজ], লাস্ট আইটেম): - শেষ (টেইল, লাস্ট আইটেম)।

উপরের কোডটি একটি তালিকার শেষ আইটেমটি দেবে। ইনপুট আরগটি প্রথম এবং ফলাফল দ্বিতীয়।

তালিকায় যদি কেবল একটি আইটেম থাকে তবে দোভাষী প্রথম সংস্করণটি বেছে নেবেন এবং দ্বিতীয় যুক্তিটি প্রথমটির সমান হিসাবে সেট করা হবে অর্থাৎ ফলাফলের জন্য একটি মান নির্ধারিত হবে।

তালিকার যদি একটি মাথা এবং একটি লেজ উভয় থাকে তবে দোভাষী দ্বিতীয় সংস্করণটি বেছে নেবেন এবং তালিকায় কেবলমাত্র একটি আইটেম অবশিষ্ট থাকবে না হওয়া পর্যন্ত পুনরাবৃত্তি করবে।


উদাহরণস্বরূপ আপনি দেখতে পাচ্ছেন যে দোভাষী নিজেও একক যুক্তিকে বিভিন্ন ভেরিয়েবলের মধ্যে স্বয়ংক্রিয়ভাবে বিভক্ত করতে পারেন (উদাহরণস্বরূপ [
শিরোনাম

4

অনেক লোকের জন্য, কিছু সহজ উদাহরণ সরবরাহ করা হলে একটি নতুন ধারণা বাছাই করা আরও সহজ, সুতরাং আমরা এখানে যাচ্ছি:

ধরা যাক আপনার কাছে তিনটি পূর্ণসংখ্যার একটি তালিকা রয়েছে এবং আপনি প্রথম এবং তৃতীয় উপাদান যুক্ত করতে চেয়েছিলেন। প্যাটার্ন মিল না থাকলে আপনি এটি এর মতো করতে পারেন (হাস্কেলের উদাহরণ):

Prelude> let is = [1,2,3]
Prelude> head is + is !! 2
4

এখন এটি খেলনার উদাহরণ হলেও, কল্পনা করুন যে আমরা প্রথম এবং তৃতীয় সংখ্যাকে ভেরিয়েবলের সাথে আবদ্ধ করতে এবং তাদের যোগফল করতে চাই:

addFirstAndThird is =
    let first = head is
        third = is !! 3
    in first + third

কোনও ডাটা স্ট্রাকচার থেকে মানগুলির এই নিষ্কাশনটি হ'ল প্যাটার্নের মিলটি কী করে। আপনি মূলত কোনও কিছুর কাঠামোটিকে "মিরর" করেন, আগ্রহের জায়গাগুলির জন্য বাঁধতে ভেরিয়েবলগুলি দিয়ে থাকেন:

addFirstAndThird [first,_,third] = first + third

আপনি যখন এই ফাংশনটিকে [1,2,3] এর যুক্তি হিসাবে কল করেন, [1,2,3] [প্রথম _, তৃতীয়] সাথে একীভূত হবে, প্রথমে 1 টি, তৃতীয় থেকে 3 আবদ্ধ হবে এবং 2 ( _স্থানধারক) যে বিষয়গুলির জন্য আপনি চিন্তা করেন না তার জন্য)।

এখন, আপনি যদি কেবল 2 টির সাথে দ্বিতীয় উপাদান হিসাবে তালিকার সাথে তাল মিলাতে চান তবে আপনি এটি এটি করতে পারেন:

addFirstAndThird [first,2,third] = first + third

এটি কেবলমাত্র 2 টির সাথে তাদের দ্বিতীয় উপাদান হিসাবে তালিকার জন্য কাজ করবে এবং অন্যথায় একটি ব্যতিক্রম ছুঁড়ে ফেলবে, কারণ অ্যাডফার্সএস্টটিয়ার্ডের সাথে কোনও মিল নেই তালিকার জন্য মিল নেই।

এখন অবধি, আমরা কেবল বাঁধাই বাঁধাইয়ের জন্য প্যাটার্ন মিলটি ব্যবহার করি। তার উপরে, আপনি একই ফাংশনের একাধিক সংজ্ঞা দিতে পারেন, যেখানে প্রথম মিলের সংজ্ঞা ব্যবহৃত হয়, সুতরাং, প্যাটার্ন মিলটি কিছুটা "স্টেরয়েডগুলির উপর একটি সুইচ স্টেটমেন্ট" এর মতো:

addFirstAndThird [first,2,third] = first + third
addFirstAndThird _ = 0

addFirstAndThird সুখের সাথে তালিকার প্রথম এবং তৃতীয় উপাদানটি 2 সহ তাদের দ্বিতীয় উপাদান হিসাবে যুক্ত করবে এবং অন্যথায় "পড়ে" এবং "ফিরুন" 0. এই "স্যুইচ-জাতীয়" কার্যকারিতা কেবল ফাংশন সংজ্ঞাতে ব্যবহৃত হতে পারে না, যেমন:

Prelude> case [1,3,3] of [a,2,c] -> a+c; _ -> 0
0
Prelude> case [1,2,3] of [a,2,c] -> a+c; _ -> 0
4

তদতিরিক্ত, এটি তালিকাগুলির মধ্যে সীমাবদ্ধ নয়, তবে অন্যান্য ধরণের সাথেও এটি ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, মানটি "মোড়ক" কাটানোর জন্য সম্ভবত টাইপের জাস্ট এবং কিছুই না মান নির্মাতাদের সাথে মেলে:

Prelude> case (Just 1) of (Just x) -> succ x; Nothing -> 0
2
Prelude> case Nothing of (Just x) -> succ x; Nothing -> 0
0

অবশ্যই, এগুলি কেবল খেলনার উদাহরণ ছিল এবং আমি এমনকি কোনও আনুষ্ঠানিক বা বিস্তৃত ব্যাখ্যা দেওয়ার চেষ্টাও করি নি, তবে তাদের প্রাথমিক ধারণাটি উপলব্ধি করার পক্ষে যথেষ্ট।


3

আপনার উইকিপিডিয়া পৃষ্ঠাটি দিয়ে শুরু করা উচিত যা একটি দুর্দান্ত ভাল ব্যাখ্যা দেয়। তারপর, প্রাসঙ্গিক অধ্যায় পড়া Haskell, উইকিবুক ইন

উপরের উইকিবুক থেকে এটি একটি দুর্দান্ত সংজ্ঞা:

সুতরাং প্যাটার্ন ম্যাচিং জিনিসগুলিতে নাম নির্ধারণের (বা সেই নামগুলিতে সেই নামগুলি আবদ্ধ করা) এবং সম্ভবত একই সাথে এক্সপ্রেসিয়নে এক্সপ্রেশনগুলি ভেঙে ফেলার এক উপায় (যেমন আমরা মানচিত্রের সংজ্ঞায় তালিকার সাথে করেছি)।


3
পরের বার আমি প্রশ্নে উল্লেখ করব যে আমি ইতিমধ্যে উইকিপিডিয়া পড়েছি এবং এটি খুব খারাপ ব্যাখ্যা দেয়।
রোমান

2

এখানে একটি প্রকৃত সংক্ষিপ্ত উদাহরণ যা প্যাটার্নের সাথে মেলে কার্যকরতা দেখায়:

ধরা যাক আপনি একটি তালিকায় একটি উপাদান বাছাই করতে চান:

["Venice","Paris","New York","Amsterdam"] 

(আমি "নিউইয়র্ক" বাছাই করেছি)

["Venice","New York","Paris","Amsterdam"] 

আরও অপরিহার্য ভাষায় আপনি লিখবেন:

function up(city, cities){  
    for(var i = 0; i < cities.length; i++){
        if(cities[i] === city && i > 0){
            var prev = cities[i-1];
            cities[i-1] = city;
            cities[i] = prev;
        }
    }
    return cities;
}

কার্যক্ষম ভাষায় আপনি পরিবর্তে লিখবেন:

let up list value =  
    match list with
        | [] -> []
        | previous::current::tail when current = value ->  current::previous::tail
        | current::tail -> current::(up tail value)

যেহেতু আপনি দেখতে পাচ্ছেন যে প্যাটার্নটি মিলছে সমাধানটিতে কম শব্দ রয়েছে, আপনি স্পষ্টভাবে দেখতে পাচ্ছেন যে বিভিন্ন কেস কী এবং এটি আমাদের তালিকা ভ্রমণ এবং ভ্রমণকে কতটা সহজ।

আমি এটি সম্পর্কে এখানে আরও বিস্তারিত ব্লগ পোস্ট লিখেছি ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.