উচ্চতর ধরণেরগুলি কখন কার্যকর হয়?


89

আমি কিছুক্ষণের জন্য F # তে ডিভ করে যাচ্ছি এবং আমি এটি পছন্দ করি। তবে আমি জানি যে একটি বাজওয়ার্ড F # তে বিদ্যমান নেই এটি হ'ল ধরণের ধরণের। আমি উচ্চ-ধরণের ধরণের উপাদানগুলি পড়েছি এবং আমি মনে করি যে আমি তাদের সংজ্ঞাটি বুঝি। কেন তারা দরকারী তা আমি নিশ্চিত নই। স্কেল বা হাস্কেল, যাতে এফ # তে কাজের ক্ষেত্র প্রয়োজন, উচ্চতর ধরণের কী কী সহজ করে তোলে তার কোনও উদাহরণ কি কেউ সরবরাহ করতে পারেন? এছাড়াও এই উদাহরণগুলির জন্য, উচ্চ ধরণের ধরণের (বা এফ # তে তদ্বিপরীত) ব্যতিরেকে কাজগুলি কী হবে? সম্ভবত আমি এটির চারপাশে কাজ করার জন্য এতটাই অভ্যস্ত হয়ে পড়েছি যে সেই বৈশিষ্ট্যের অনুপস্থিতি আমি লক্ষ্য করি না।

(আমি মনে করি) আমি পেয়েছি যে পরিবর্তে myList |> List.map fবা myList |> Seq.map f |> Seq.toListউচ্চতর ধরণের আপনাকে কেবল লেখার অনুমতি দেয় myList |> map fএবং এটি একটি ফিরে আসবে List। এটি দুর্দান্ত (এটি সঠিক বলে ধরে নিচ্ছেন), তবে কি একরকম ছোটখাটো বলে মনে হচ্ছে? (এবং কেবল ফাংশন ওভারলোডিংকে অনুমতি দিয়ে এটি করা যায়নি?) আমি সাধারণত Seqযেভাবেই রূপান্তর করি এবং তারপরে আমি যা চাই তা রূপান্তর করতে পারি। আবার, সম্ভবত আমি এটি প্রায় কাজ করতে অভ্যস্ত। তবে এমন কোনও উদাহরণ রয়েছে যেখানে উচ্চতর ধরণের ধরণের প্রকৃতপক্ষে কীট্রোকগুলিতে বা প্রকার সুরক্ষায় আপনাকে বাঁচায়?


4
কন্ট্রোল.মোনাদে অনেকগুলি ফাংশন উচ্চতর ধরণের ব্যবহার করে যাতে আপনি কয়েকটি উদাহরণের জন্য সেখানে দেখতে চান। এফ # তে প্রতিটি কংক্রিট মোনাড ধরণের জন্য বাস্তবায়নগুলি পুনরাবৃত্তি করতে হবে।
লি

4
@ শুনুন তবে আপনি কেবল একটি ইন্টারফেস তৈরি করতে পারবেন না IMonad<T>এবং তারপরে এটিকে আবার কাস্ট করতে পারবেন IEnumerable<int>বা IObservable<int>আপনি যখন হয়ে গেছেন ? এই সব কি কেবল কাস্টিং এড়ানোর জন্য?
লবস্টারিজম

4
ভাল castালাই অনিরাপদ, যাতে প্রকারের সুরক্ষা সম্পর্কে আপনার প্রশ্নের উত্তর দেয়। আর একটি বিষয় হ'ল এটি কীভাবে returnকাজ করবে যেহেতু এটি সত্যই মোনাড টাইপের সাথে সম্পর্কিত, কোনও নির্দিষ্ট উদাহরণ নয় যাতে আপনি একে একে IMonadইন্টারফেসে রাখতে চান না ।
লি

4
@ হ্যাঁ আমি কেবল ভাবছিলাম যে আপনাকে প্রকাশের পরে চূড়ান্ত ফলাফলটি দিতে হবে, কোনও বড় কথা নেই কারণ আপনি কেবল প্রকাশটি তৈরি করেছেন যাতে আপনি টাইপটি জানতে পারেন। কিন্তু এটা দেখে মনে হচ্ছে তোমরা প্রত্যেকে impl ভিতরে নিক্ষেপ করা আছে চাই bindওরফে SelectManyইত্যাদি খুব। কাউকে এপিআই ব্যবহার করতে পারে যার মানে bindএকটি IObservableএকটি থেকে IEnumerableএবং, এটা কাজ করবে অনুমান যা হাঁ Yuck সেই বিষয়টিই কিনা তা সেখানে প্রায় কোন উপায়। এটির আশেপাশে কোনও উপায় নেই 100% নিশ্চিত না।
লবস্টারিজম

6
দুর্দান্ত প্রশ্ন। আমি এখনও এই ভাষার বৈশিষ্ট্যটির কার্যকর আইআরএল হওয়ার একক আকর্ষণীয় ব্যবহারিক উদাহরণ দেখতে পাইনি।
জেডি

উত্তর:


79

সুতরাং একটি ধরণের ধরণ এটি এর সহজ প্রকার। উদাহরণস্বরূপ Intধরণের রয়েছে *যার অর্থ এটি একটি বেস টাইপ এবং মানগুলির মাধ্যমে তা ইনস্ট্যান্ট করা যায়। উচ্চ kinded ধরনের কিছু আলগা সংজ্ঞা দ্বারা (এবং আমি নিশ্চিত যেখানে এফ # লাইন স্বপক্ষে নই, তাই আসুন শুধু তা অন্তর্ভুক্ত দিন) বহুরুপী পাত্রে একটি উচ্চ-kinded ধরনের একটি বড় উদাহরণ আছে।

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

টাইপ কন্সট্রাক্টরের টাইপ Listরয়েছে * -> *যার অর্থ একটি কংক্রিট টাইপের ফলস্বরূপ এটি একটি কংক্রিট টাইপ পাস করতে হবে: এর List Intমতো বাসিন্দা থাকতে পারে [1,2,3]তবে Listনিজেই পারে না।

আমি ধরে নিচ্ছি যে পলিমারফিক পাত্রে সুবিধাগুলি সুস্পষ্ট, তবে * -> *কেবল ধারকগুলির চেয়ে আরও দরকারী ধরণের প্রকারের উপস্থিতি রয়েছে। উদাহরণস্বরূপ, সম্পর্ক

data Rel a = Rel (a -> a -> Bool)

বা পার্সার্স

data Parser a = Parser (String -> [(a, String)])

উভয়েরও সদয় হয় * -> *


আমরা এটি আরও উচ্চতর ক্রমযুক্ত ধরণের ধরণের মাধ্যমে, হাস্কেলগুলিতে আরও এগিয়ে নিতে পারি। উদাহরণস্বরূপ আমরা ধরনের সঙ্গে একটি টাইপ জন্য সন্ধান করতে পারে (* -> *) -> *। এটির একটি সাধারণ উদাহরণ হতে পারে Shapeযা কোনও ধরণের পাত্রে ভরাট করার চেষ্টা করে * -> *

data Shape f = Shape (f ())

[(), (), ()] :: Shape List

এটি Traversableহাস্কেল-এর বৈশিষ্ট্যগুলির জন্য দরকারী , উদাহরণস্বরূপ, কারণ তারা সর্বদা তাদের আকার এবং বিষয়বস্তুগুলিতে বিভক্ত হতে পারে।

split :: Traversable t => t a -> (Shape t, [a])

অন্য উদাহরণ হিসাবে, আসুন এমন একটি গাছ বিবেচনা করুন যা এটির শাখাটির পরামিতি রয়েছে। উদাহরণস্বরূপ, একটি সাধারণ গাছ হতে পারে

data Tree a = Branch (Tree a) a (Tree a) | Leaf

কিন্তু আমরা দেখতে পাচ্ছি শাখা ধরনের একটি রয়েছে Pairএর Tree as এবং তাই আমরা parametrically ধরনের আউট যে টুকরা নিষ্কাশন করতে পারেন

data TreeG f a = Branch a (f (TreeG f a)) | Leaf

data Pair a = Pair a a
type Tree a = TreeG Pair a

এই TreeGধরণের কন্সট্রাক্টর ধরনের আছে (* -> *) -> * -> *। আমরা এটির মতো আকর্ষণীয় অন্যান্য রূপগুলি তৈরি করতে এটি ব্যবহার করতে পারিRoseTree

type RoseTree a = TreeG [] a

rose :: RoseTree Int
rose = Branch 3 [Branch 2 [Leaf, Leaf], Leaf, Branch 4 [Branch 4 []]]

বা প্যাথলজিকাল একটি যেমন MaybeTree

data Empty a = Empty
type MaybeTree a = TreeG Empty a

nothing :: MaybeTree a
nothing = Leaf

just :: a -> MaybeTree a
just a = Branch a Empty

বা ক TreeTree

type TreeTree a = TreeG Tree a

treetree :: TreeTree Int
treetree = Branch 3 (Branch Leaf (Pair Leaf Leaf))

এটি প্রদর্শিত অন্য একটি জায়গা হ'ল "ফান্টারের বীজগণিত"। যদি আমরা বিমূর্ততার কয়েকটি স্তর ফেলে রাখি তবে এটিকে আরও ভাল ভাঁজ হিসাবে বিবেচনা করা যেতে পারে sum :: [Int] -> Int। বীজগণিতগুলি ফান্টেক্টর এবং ক্যারিয়ারের উপরে প্যারামিটারাইজড হয় । Functor ধরনের রয়েছে * -> *এবং ক্যারিয়ার ধরনের *তাই পুরাপুরি

data Alg f a = Alg (f a -> a)

দয়ালু আছে (* -> *) -> * -> *Algডেটাটাইপগুলির সাথে সম্পর্কিত এবং তাদের উপরে নির্মিত পুনরাবৃত্তি স্কিমগুলির কারণে দরকারী।

-- | The "single-layer of an expression" functor has kind `(* -> *)`
data ExpF x = Lit Int
            | Add x x
            | Sub x x
            | Mult x x

-- | The fixed point of a functor has kind `(* -> *) -> *`
data Fix f = Fix (f (Fix f))

type Exp = Fix ExpF

exp :: Exp
exp = Fix (Add (Fix (Lit 3)) (Fix (Lit 4))) -- 3 + 4

fold :: Functor f => Alg f a -> Fix f -> a
fold (Alg phi) (Fix f) = phi (fmap (fold (Alg phi)) f)

পরিশেষে, যদিও তারা তাত্ত্বিকভাবে সম্ভব, আমি এর চেয়েও উচ্চতর ধরণের নির্মাণকারী কখনও দেখিনি । আমরা কখনও কখনও সেই ধরণের ফাংশন দেখতে পাই mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b, তবে আমি মনে করি যে প্রকার জটিলতার সেই স্তরটি দেখতে আপনাকে প্রলোগ টাইপ করুন বা নির্ভরশীল টাইপ করা সাহিত্যের মধ্যে খনন করতে হবে।


4
আমি কয়েক মিনিটের মধ্যে কোডটি টাইপ-চেক করব এবং সম্পাদনা করব, আমি এখনই আমার ফোনে আছি।
জে আব্রাহামসন

12
একটি ভাল উত্তরের জন্য @ জে.আব্রাহামসনকে +1 করুন এবং আপনার ফোনে টাইপ করার ধৈর্য ধারণ করে ও_ও
ড্যানিয়েল গ্রেটজার

4
@ ল্যাবস্টেরিজম এ TreeTreeকেবল প্যাথলজিকাল, তবে আরও ব্যবহারিকভাবে এর অর্থ হ'ল আপনি একে অপরের মধ্যে জড়িত দুটি ভিন্ন ধরণের গাছ পেয়েছেন that এই ধারণাটিকে আরও কিছুটা এগিয়ে নিয়ে যাওয়া আপনাকে স্ট্যাটিকালি-নিরাপদ লাল / কালো গাছ এবং ঝরঝরে স্থিতিশীলভাবে সুষম ফিঙ্গার ট্রি প্রকার।
জে আব্রাহামসন

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

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

64

Functorহাস্কেলের ধরণের শ্রেণি বিবেচনা করুন , যেখানে fউচ্চতর ধরণের ধরণের পরিবর্তনশীল:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

কি এই ধরনের স্বাক্ষর বলছেন যে fmap একটি ধরণ প্যারামিটার পরিবর্তন হয় fথেকে aথেকে b, কিন্তু পাতার fযেমন ছিল। সুতরাং আপনি যদি fmapকোনও তালিকার উপরে ব্যবহার করেন তবে আপনি একটি তালিকা পান, আপনি যদি এটি কোনও পার্সারের সাহায্যে ব্যবহার করেন তবে আপনি পার্সার পাবেন এবং আরও কিছু। এবং এগুলি স্থির , সংকলন-সময়ের গ্যারান্টি।

আমি এফ # জানি না, তবে আসুন আমরা যদি Functorজাভা বা সি # এর মতো ভাষাতে উত্তরাধিকার এবং জেনেরিক সহ, তবে উচ্চতর ধরণের জেনেরিকগুলি প্রকাশ করার চেষ্টা না করি তবে কী ঘটে তা বিবেচনা করা যাক । প্রথম চেষ্টা:

interface Functor<A> {
    Functor<B> map(Function<A, B> f);
}

এই প্রথম চেষ্টাটির সাথে সমস্যাটি হ'ল ইন্টারফেসের প্রয়োগের ফলে প্রয়োগ করা কোনও শ্রেণি ফেরত দেওয়া যায় Functor। এমন কেউ লিখতে পারেন FunnyList<A> implements Functor<A>যার mapপদ্ধতিতে ভিন্ন ধরণের সংগ্রহ পাওয়া যায়, বা এমন কোনও কিছু যা কোনও সংগ্রহ নয় তবে এটি এখনও একটি Functor। এছাড়াও, আপনি যখন mapপদ্ধতিটি ব্যবহার করেন আপনি ফলাফলের উপর কোনও ধরণের টাইপ-নির্দিষ্ট পদ্ধতিতে আবেদন করতে পারবেন না যদি না আপনি এটি যে ধরণের প্রত্যাশা করছেন তার সাথে এটি বাদ দেন। সুতরাং আমাদের দুটি সমস্যা আছে:

  1. প্রকারের ব্যবস্থাটি আমাদের আক্রমণকারীটিকে প্রকাশ করতে দেয় না যে mapপদ্ধতিটি সর্বদা Functorরিসিভারের মতো একই সাবক্লাসটি দেয় returns
  2. অতএব, Functorফলাফলের জন্য কোনও অ-পদ্ধতিতে প্রার্থনা করার জন্য কোনও স্ট্যাটিকালি টাইপ-নিরাপদ উপায় নেই map

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

interface Collection<A> extends Functor<A> {
    Collection<B> map(Function<A, B> f);
}

interface List<A> extends Collection<A> {
    List<B> map(Function<A, B> f);
}

interface Set<A> extends Collection<A> {
    Set<B> map(Function<A, B> f);
}

interface Parser<A> extends Functor<A> {
    Parser<B> map(Function<A, B> f);
}

// …

এটি সেই সংকীর্ণ ইন্টারফেসগুলির প্রয়োগকারীদের পদ্ধতি Functorথেকে ভুল ধরণের প্রত্যাবর্তন করতে নিষেধ করতে সহায়তা করে map, তবে যেহেতু Functorআপনার কতগুলি বাস্তবায়ন হতে পারে তার সীমাবদ্ধতা নেই, আপনার কত সংকীর্ণ ইন্টারফেসের প্রয়োজন হবে তার সীমা নেই is

( সম্পাদনা করুন: এবং মনে রাখবেন এই শুধুমাত্র কাজ করে কারণ Functor<B>প্রদর্শিত হয় ফলাফলের প্রকার, এবং তাই সন্তানের ইন্টারফেসগুলি এটা সংকীর্ণ পারেন তাই আমি যতদূর জানি আমরা উভয় ব্যবহারসমূহ সংকীর্ণ করতে পারবে না। Monad<B>নিম্নলিখিত ইন্টারফেসে:

interface Monad<A> {
    <B> Monad<B> flatMap(Function<? super A, ? extends Monad<? extends B>> f);
}

মধ্যে Haskell, উচ্চ-সারির টাইপ ভেরিয়েবল সঙ্গে, এই হল (>>=) :: Monad m => m a -> (a -> m b) -> m b।)

তবুও আরেকটি চেষ্টা হ'ল পুনরাবৃত্ত জেনারিকগুলি ব্যবহার করার চেষ্টা করার জন্য এবং ইন্টারফেসটি সাব টাইপের ফলাফলের ধরণটি কেবল সাব টাইপের মধ্যে সীমাবদ্ধ করে রাখে। খেলনা উদাহরণ:

/**
 * A semigroup is a type with a binary associative operation.  Law:
 *
 * > x.append(y).append(z) = x.append(y.append(z))
 */
interface Semigroup<T extends Semigroup<T>> {
    T append(T arg);
}

class Foo implements Semigroup<Foo> {
    // Since this implements Semigroup<Foo>, now this method must accept 
    // a Foo argument and return a Foo result. 
    Foo append(Foo arg);
}

class Bar implements Semigroup<Bar> {
    // Any of these is a compilation error:

    Semigroup<Bar> append(Semigroup<Bar> arg);

    Semigroup<Foo> append(Bar arg);

    Semigroup append(Bar arg);

    Foo append(Bar arg);

}

তবে এই ধরণের কৌশল (যা আপনার ওপেন-মিল-র ওওপি বিকাশকারীর কাছে বরং তীরযুক্ত, আপনার রান-অফ-দ্য মিল-র কার্যকারিতা বিকাশকারীকেও হ্যাক করুন) এখনও কাঙ্ক্ষিত Functorবাধা প্রকাশ করতে পারে না :

interface Functor<FA extends Functor<FA, A>, A> {
    <FB extends Functor<FB, B>, B> FB map(Function<A, B> f);
}

সমস্যা এখানে এই সীমিত নয় FBএকই আছে Fহিসাবে FA-so যখন আপনি একটি টাইপ ঘোষণা করছি যে List<A> implements Functor<List<A>, A>, mapপদ্ধতি করতে এখনো একটি ফিরতি NotAList<B> implements Functor<NotAList<B>, B>

জাভাতে কাঁচা ধরণের (অপরিশোধিত পাত্রে) ব্যবহার করে চূড়ান্ত চেষ্টা করুন:

interface FunctorStrategy<F> {
    F map(Function f, F arg);
} 

এখানে Fকেবল Listবা এর মতো অপরিশোধিত প্রকারভেদে তাত্ক্ষণিকভাবে আসবে Map। এটি গ্যারান্টি দেয় যে একজন FunctorStrategy<List>কেবলমাত্র ফিরিয়ে দিতে পারে List- তবে আপনি তালিকার উপাদানগুলির ধরনগুলি ট্র্যাক করতে টাইপ ভেরিয়েবলের ব্যবহার পরিত্যাগ করেছেন।

এখানে সমস্যার কেন্দ্রস্থল হ'ল জাভা এবং সি # এর মতো ভাষা টাইপ পরামিতিগুলিকে পরামিতি রাখতে দেয় না। জাভা, যদি Tএকটি টাইপ পরিবর্তনশীল, আপনি লিখতে পারেন Tএবং List<T>, কিন্তু না T<String>। উচ্চ-ধরণের ধরণের ধরণগুলি এই বিধিনিষেধটি সরিয়ে দেয়, যাতে আপনার এমন কিছু থাকতে পারে (পুরোপুরি ভাবেননি):

interface Functor<F, A> {
    <B> F<B> map(Function<A, B> f);
}

class List<A> implements Functor<List, A> {

    // Since F := List, F<B> := List<B>
    <B> List<B> map(Function<A, B> f) {
        // ...
    }

}

এবং এই বিট বিশেষভাবে সম্বোধন:

(আমি মনে করি) আমি পেয়েছি যে পরিবর্তে myList |> List.map fবা myList |> Seq.map f |> Seq.toListউচ্চতর ধরণের আপনাকে কেবল লেখার অনুমতি দেয় myList |> map fএবং এটি একটি ফিরে আসবে List। এটি দুর্দান্ত (এটি সঠিক বলে ধরে নিচ্ছেন), তবে কি একরকম ছোটখাটো বলে মনে হচ্ছে? (এবং কেবল ফাংশন ওভারলোডিংকে অনুমতি দিয়ে এটি করা যায়নি?) আমি সাধারণত Seqযেভাবেই রূপান্তর করি এবং তারপরে আমি যা চাই তা রূপান্তর করতে পারি।

এমন অনেকগুলি ভাষা রয়েছে যা এইভাবে mapফাংশনটির ধারণাটিকে সাধারণীকরণ করে , একে মডেলিং করে যেমন হৃদয়ে, ম্যাপিংটি সিকোয়েন্সগুলি সম্পর্কে। পুলিশের এই মন্তব্য যে আত্মা রয়েছে: যদি আপনি একটি যে ধরনের এবং থেকে সমর্থন রূপান্তর আছে Seq, আপনি পুনঃব্যবহার দ্বারা "বিনামূল্যে জন্য" মানচিত্র অপারেশন পেতে Seq.map

হাসকেলে অবশ্য Functorক্লাসটি তার চেয়ে বেশি সাধারণ; এটি অনুক্রমের ধারণার সাথে আবদ্ধ নয়। fmapক্রম IO, পার্সার সংযুক্তকারী, ফাংশন ইত্যাদির মতো সিকোয়েন্সগুলিতে ভাল ম্যাপিং নেই এমন প্রকারের জন্য আপনি প্রয়োগ করতে পারেন . :

instance Functor IO where
    fmap f action =
        do x <- action
           return (f x)

 -- This declaration is just to make things easier to read for non-Haskellers 
newtype Function a b = Function (a -> b)

instance Functor (Function a) where
    fmap f (Function g) = Function (f . g)  -- `.` is function composition

"ম্যাপিং" ধারণাটি আসলেই অনুক্রমের সাথে আবদ্ধ নয়। ফান্টারের আইনগুলি বোঝা ভাল:

(1) fmap id xs == xs
(2) fmap f (fmap g xs) = fmap (f . g) xs

খুব অনানুষ্ঠানিকভাবে:

  1. প্রথম আইনটি বলে যে কোনও পরিচয় / নূপুর ফাংশন সহ ম্যাপিং কিছুই না করার মতো।
  2. দ্বিতীয় আইন বলছে যে আপনি দুবার ম্যাপিংয়ের মাধ্যমে যে কোনও ফলাফল তৈরি করতে পারেন, আপনি একবার ম্যাপিংয়ের মাধ্যমেও উত্পাদন করতে পারেন।

এ কারণেই আপনি fmapটাইপটি সংরক্ষণ করতে চান — কারণ আপনি যেমন mapকোনও ভিন্ন ফলাফলের প্রকার উত্পাদন করে এমন অপারেশনগুলি পাওয়ার সাথে সাথে এটির গ্যারান্টি দেওয়া অনেক বেশি শক্ত হয়ে যায়।


সুতরাং আমি আপনার শেষ বিটটিতে আগ্রহী, ইতিমধ্যে এটির অপারেশন fmapহওয়ার Function aপরে কেন এটি দরকারী .? আমি কেন বুঝতে পারি যে .এই fmapবিকল্পটির সংজ্ঞা হিসাবে বোধগম্যতা বোধ করা হয়েছে , তবে যেখানে আপনি কখনও তার fmapপরিবর্তে কখন ব্যবহার করতে হবে তা আমি পাই না .। সম্ভবত আপনি যদি উদাহরণটি দিতে পারেন যেখানে এটি কার্যকর হবে তবে এটি আমাকে বুঝতে সহায়তা করবে।
লবস্টারিজম 18'14

4
আহ, এটি পেয়েছেন: আপনি কোনও ফান্টারের একটি এফএন তৈরি করতে পারেন double, যেখানে পাপের দ্বিগুণ পরিমাণে একটি এফএন double [1, 2, 3]দেয় [2, 4, 6]এবং double sinদেয়। আমি দেখতে পাচ্ছি আপনি যদি সেই মানসিকতায় চিন্তা শুরু করেন, যখন আপনি কোনও অ্যারেতে কোনও মানচিত্র চালাবেন আপনি কেবল একটি সিক নয়, একটি অ্যারের ফিরে প্রত্যাশা করবেন কারণ, ভাল, আমরা এখানে অ্যারেগুলিতে কাজ করছি।
লবস্টারিজম

@ ল্যাবস্টেরিজম: এমন অ্যালগরিদম / কৌশল রয়েছে যা একটি বিমূর্ততা বের করতে সক্ষম হয় Functorএবং লাইব্রেরির ক্লায়েন্টটিকে এটি খুঁজে নিতে দেয়। জে আব্রাহামসনের উত্তরের একটি উদাহরণ সরবরাহ করা হয়েছে: ফ্যান্টেক্টর ব্যবহার করে পুনরাবৃত্ত হওয়া ভাঁজগুলি সাধারণ করা যায়। আরেকটি উদাহরণ হ'ল ফ্রি মনাদ; আপনি এগুলিকে এক ধরণের জেনেরিক ইন্টারপ্রেটার বাস্তবায়ন লাইব্রেরি হিসাবে ভাবতে পারেন, যেখানে ক্লায়েন্ট "ইন্সট্রাকশন সেট" স্বেচ্ছাসেবীর হিসাবে সরবরাহ করে Functor
লুইস ক্যাসিলাস

4
একটি প্রযুক্তিগত দিক থেকে উত্তম উত্তর তবে এটি কেন ভাবছে যে কেউ কেন বাস্তবে এটি চাইবে। আমি নিজেকে হাস্কেল Functorবা এ-তে পৌঁছতে পাইনি SemiGroup। আসল প্রোগ্রামগুলি এই ভাষার বৈশিষ্ট্যটি সর্বাধিক কোথায় ব্যবহার করে?
জেডি

28

আমি ইতিমধ্যে এখানে কিছু দুর্দান্ত উত্তরে তথ্য পুনরাবৃত্তি করতে চাই না, তবে একটি মূল পয়েন্ট আমি যুক্ত করতে চাই।

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

সাধারণভাবে আমি দেখতে পেয়েছি যে লোকেরা যখন ফান্ট্যাকার / মনড / তড়িঘড়িগুলির কার্যকারিতা দেখতে পায় না তখন এটি প্রায়শই হয় কারণ তারা একবারে এই জিনিসগুলি নিয়ে ভাবছে । ফান্টেক্টর / মোনাড / ইত্যাদি ক্রিয়াকলাপগুলি সত্যিই কোনও উদাহরণে কিছু যোগ করে না (বাঁধাই, এফএমএপি ইত্যাদি কল করার পরিবর্তে আমি কেবল বাইন্ড, এফএমএপি, ইত্যাদি প্রয়োগ করতে যা কিছু অপারেশন কল করতে পারি )। আপনি এই বিমূর্ততাগুলির জন্য যা চান তা হ'ল যাতে আপনার কোনও কোড থাকতে পারে যা কোনও ফান্টার / মোনাড / ইত্যাদির সাথে সাধারণভাবে কাজ করে ।

এমন প্রসঙ্গে যেখানে এই জাতীয় জেনারিক কোডটি ব্যাপকভাবে ব্যবহৃত হয়, এর অর্থ আপনি যখনই কোনও নতুন মোনাড লিখেন তখন আপনার ধরণটি তত্ক্ষণাত আপনার জন্য ইতিমধ্যে লেখা রয়েছে এমন বিশাল সংখ্যক দরকারী অপারেশনে অ্যাক্সেস অর্জন করে । এটি সর্বত্র monads (এবং ফান্টেক্টর, এবং ...) দেখার বিষয়; আমি এর bindপরিবর্তে concatএবং mapপ্রয়োগ করতে myFunkyListOperation(যা আমাকে নিজের মধ্যে কিছুই লাভ করে না) ব্যবহার করতে পারি না , বরং যাতে যখন আমার প্রয়োজন হয় myFunkyParserOperationএবং myFunkyIOOperationতালিকার সাথে আমি যে কোডটি দেখেছিলাম সেগুলি পুনরায় ব্যবহার করতে পারি কারণ এটি আসলে মোনাড-জেনেরিক ।

তবে টাইপ সুরক্ষার সাথে একটি প্যারামিতি টাইপের মতো মনোডের মতো বিমূর্তকরণের জন্য আপনার উচ্চতর ধরণের (যেমন অন্যান্য উত্তরগুলিতে এখানেও ব্যাখ্যা করেছেন) প্রয়োজন।


9
আমি এখনও অবধি পড়ে থাকা অন্যান্য উত্তরগুলির তুলনায় এটি একটি দরকারী উত্তর হওয়ার কাছাকাছি তবে আমি এখনও একটি একক ব্যবহারিক অ্যাপ্লিকেশন দেখতে চাই যেখানে উচ্চতর ধরণের কার্যকর।
জেডি

"আপনি এই বিমূর্ততাগুলির জন্য যা চান তা হ'ল যাতে আপনার কোনও কোড থাকতে পারে যা কোনও ফান্টার / মোনাডের সাথে উদারভাবে কাজ করে"। এফ # 13 বছর আগে গণনা এক্সপ্রেশন আকারে monads পেয়েছে, মূলত স্পোর্টিং সেক এবং অ্যাসিঙ্ক মনডস। আজ এফ # 3 তম মোনাদ উপভোগ করেছে, ক্যোয়ারী। এত কম কিছু সন্ন্যাসের সাথে খুব সামান্য মিল রয়েছে কেন আপনি তাদের উপর বিমূর্ত করতে চান?
জেডি

@ জোনহরপ আপনি স্পষ্টভাবেই অবগত আছেন যে অন্যান্য লোকেরা এইচকেটি সমর্থন করে এমন ভাষায় বিপুল সংখ্যক মনাদ (এবং ফান্টরস, তীর ইত্যাদি;) এইচকেটিগুলি কেবল মনাদ সম্পর্কে নয়) ব্যবহার করে কোড লিখেছেন এবং তাদের উপর বিমূর্ত করার জন্য ব্যবহারগুলি খুঁজে পান। এবং স্পষ্টতই আপনি ভাবেন না যে এই কোডটির কোনওটিরই ব্যবহারিক ব্যবহার রয়েছে এবং কৌতূহল রয়েছে কেন অন্য লোকেরা এটি লিখতে বিরক্ত করবেন। আপনি ইতিমধ্যে 5 বছর পূর্বে মন্তব্য করেছেন এমন 6 বছরের পুরানো পোস্টে বিতর্ক শুরু করতে ফিরে এসে আপনি কী ধরণের অন্তর্দৃষ্টি লাভের আশা করছেন?
বেন

"6 বছরের পুরানো পোস্টে বিতর্ক শুরু করতে ফিরে এসে লাভের আশা"। পূর্ববর্তী অন্ধত্বের উপকারের সাথে আমরা এখন জানি যে F # এর বিমূর্ততা monades উপর মূলত অব্যবহৃত রয়ে গেছে। অতএব 3 টির বেশি বিস্তৃত জিনিস বিমূর্ত করার ক্ষমতা আপত্তিহীন।
জেডি

@ জোনহরপ আমার উত্তরের বিষয়টি হ'ল পৃথক মনড (বা ফান্টেক্টর, বা ইত্যাদি) যাযাবর ইন্টারফেস ছাড়াই প্রকাশিত অনুরূপ কার্যকারিতার চেয়ে বেশি কার্যকর কিছু নয়, তবে প্রচুর স্বতন্ত্র জিনিসগুলিকে একত্রিত করার বিষয়টি। আমি এফ # তে আপনার দক্ষতা মুলতবি করব, তবে আপনি যদি বলছেন তবে এটিতে কেবল 3 টি পৃথক মনাদ রয়েছে (ব্যর্থতা, রাষ্ট্রীয়তা, পার্সিং ইত্যাদির মতো একটি ধারণার মধ্যে একটি একক ইন্টারফেস প্রয়োগের পরিবর্তে), তবে হ্যাঁ, এটি আশ্চর্যজনক যে এই 3 টি জিনিসকে এক করে দেওয়ার মাধ্যমে আপনি খুব বেশি সুবিধা পাবেন না।
বেন

15

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

আপনি যে নিকটতম পেলেন (ব্লগ পোস্ট করার পরে আমি বুঝতে পেরেছি) তা হ'ল নিজের তৈরি করা IEnumerable<T>এবং এটি IObservable<T>দুটি থেকে প্রসারিত করা IMonad<T>। এটি আপনাকে আপনার লিনকিউ ব্লকগুলি চিহ্নিত করা থাকলে পুনরায় ব্যবহার করার অনুমতি দেয় IMonad<T>, তবে এটি আর টাইপসেফ নেই কারণ এটি আপনাকে মেশানো এবং মিল করতে দেয় IObservablesএবং IEnumerablesএকই ব্লকের মধ্যে যা এটি সক্ষম করতে আগ্রহী মনে হতে পারে, আপনি চাইতেন মূলত কিছু অপরিজ্ঞাত আচরণ পান।

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


4
আমি একমাত্র উত্তর হওয়ার জন্য আপনাকে একটি +1 দেব যাতে ব্যবহারিক কিছু উল্লেখ করা হয়েছে তবে আমি মনে করি না যে আমি কখনও IObservablesউত্পাদন কোড ব্যবহার করেছি ।
জেডি

4
পছন্দ করুন এফ # তে সমস্ত ইভেন্ট হয় IObservableএবং আপনি নিজের বইয়ের উইনফোর্ডস অধ্যায়টিতে ইভেন্টগুলি ব্যবহার করেন।
ডেক্স ফোহল

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

আইকোয়ারেবল এবং আইউনামেবলের মধ্যে পুনরায় ব্যবহার করা সম্ভব হবে আমিও মনে করি
কোলা

চার বছর পরে এবং আমি দেখতে শেষ করেছি: আমরা আরএক্সকে উত্পাদন থেকে সরিয়ে নিয়েছি।
জেডি

13

হাস্কেলের মধ্যে উচ্চ-ধরণের টাইপ পলিমারফিজমের সর্বাধিক ব্যবহৃত উদাহরণ হ'ল Monadইন্টারফেস। Functorএবং Applicativeএকইভাবে উচ্চ-দয়ালু, তাই আমি Functorসংক্ষিপ্ত কিছু দেখানোর জন্য প্রদর্শন করব ।

class Functor f where
    fmap :: (a -> b) -> f a -> f b

এখন, সংজ্ঞাটি পরীক্ষা করে দেখুন কীভাবে ভেরিয়েবল টাইপ fব্যবহৃত হয় তা দেখে। আপনি দেখতে পাবেন এর fঅর্থ এমন কোনও প্রকারের অর্থ হতে পারে না। আপনি সেই ধরণের স্বাক্ষরে মানগুলি সনাক্ত করতে পারেন কারণ তারা কোনও ফাংশনের যুক্তি এবং ফলাফল। সুতরাং ভেরিয়েবল টাইপ করুন aএবং bএমন ধরণ যা মান থাকতে পারে। টাইপ এক্সপ্রেশন f aএবং হয় f b। তবে fনিজেই নয়। fএকটি উচ্চ ধরণের ধরণের পরিবর্তনশীল একটি উদাহরণ। প্রদত্ত যে *মান করতে পারে ধরনের ধরনের, fধরনের থাকতে হবে * -> *। অর্থাৎ এটি একটি টাইপ মান করতে পারে, কারণ আমরা পূর্ববর্তী পরীক্ষার থেকে জানি যে সময় লাগে aএবং bমান থাকা আবশ্যক। এবং আমরা জানি যে f aএবংf b মান থাকতে হবে, সুতরাং এটি এমন একটি টাইপ দেয় যা মান থাকতে হবে।

এটি উচ্চতর ধরণের ধরণের পরিবর্তনশীল সংজ্ঞাতে fব্যবহৃত হয় Functor

Applicativeএবং Monadইন্টারফেস আরো যোগ, কিন্তু তারা সামঞ্জস্যপূর্ণ। এর অর্থ তারা প্রকারের সাথে টাইপ ভেরিয়েবলগুলিতেও কাজ করে * -> *

উচ্চতর ধরণের ধরণের উপর কাজ করা বিমূর্ততার একটি অতিরিক্ত স্তরের পরিচয় দেয় - আপনি কেবলমাত্র প্রাথমিক ধরণের উপর বিমূর্ততা তৈরি করতে সীমাবদ্ধ নন। আপনি অন্যান্য ধরণের পরিবর্তনকারী প্রকারের উপর বিমূর্ততাও তৈরি করতে পারেন।


4
কী ধরণের উচ্চতরগুলির আরও একটি দুর্দান্ত প্রযুক্তিগত ব্যাখ্যা যা সেগুলির জন্য দরকারী তা ভেবে আমাকে ছেড়ে যায়। আপনি সত্যিকারের কোডটিতে এটি কোথায় ব্যবহার করেছেন?
জেডি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.