হাস্কেলগুলিতে কি "এক ধরণের মাত্রা বেক করা" সম্ভব?


20

মনে করুন আমি এমন একটি লাইব্রেরি লিখতে চাই যা ভেক্টর এবং ম্যাট্রিক্স নিয়ে কাজ করে। প্রকারগুলিতে মাত্রা বেক করা কি সম্ভব, যাতে বেমানান মাত্রার ক্রিয়াকলাপগুলি সংকলনের সময় ত্রুটি সৃষ্টি করে?

উদাহরণস্বরূপ আমি চাই বিন্দু পণ্যের স্বাক্ষরটি এমন কিছু হোক

dotprod :: Num a, VecDim d => Vector a d -> Vector a d -> a

যেখানে dটাইপটিতে একটি একক পূর্ণসংখ্যার মান থাকে (এই ভেক্টরের মাত্রা উপস্থাপন করে)।

আমি অনুমান করি যে প্রতিটি পূর্ণসংখ্যার জন্য পৃথক প্রকারের (হাতের) সংজ্ঞা দিয়ে এবং এটি একটি টাইপ শ্রেণীর মধ্যে গোষ্ঠীবদ্ধ করে কাজটি করা যেতে পারে VecDim। এই জাতীয় ধরণের "উত্পন্ন" করার কোনও ব্যবস্থা আছে কি?

অথবা সম্ভবত একই জিনিস অর্জনের কিছু ভাল / সহজ উপায়?


3
হ্যাঁ, আমি যদি সঠিকভাবে মনে করি তবে হাসকেলে নির্ভরশীল টাইপিংয়ের এই প্রাথমিক স্তরের সরবরাহ করার জন্য গ্রন্থাগার রয়েছে। আমি একটি ভাল উত্তর প্রদান করা যদিও যথেষ্ট পরিচিত না।
তেলস্তিন

চারদিকে তাকালে মনে হয় tensorলাইব্রেরিটি পুনরাবৃত্ত dataসংজ্ঞাটি ব্যবহার করে এটি বেশ মার্জিতভাবে অর্জন করছে : noaxiom.org/tensor-docamentation#ordinals
মিচুস

এটি স্কেলা, হ্যাশেল নয়, তবে এটি নির্ভরশীল ধরণের পাশাপাশি ভেক্টরগুলির মিলহীন "প্রকার" প্রতিরোধের জন্য নির্ভরশীল প্রকারগুলি ব্যবহার সম্পর্কে কিছু সম্পর্কিত ধারণা রয়েছে। chrisstucchio.com/blog/2014/…
দেনিথ

উত্তর:


32

@ কার্লবিলিফেল্টের উত্তরে সম্প্রসারণের জন্য, এখানে ভেক্টরগুলি কীভাবে প্রয়োগ করা যায় তার একটি সম্পূর্ণ উদাহরণ - হাসকেলে স্ট্যাটিক্যালি পরিচিত সংখ্যার তালিকা রয়েছে। আপনার টুপি ধরুন ...

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}

import Prelude hiding (foldr, zipWith)
import qualified Prelude
import Data.Type.Equality
import Data.Foldable
import Data.Traversable

আপনি LANGUAGEনির্দেশের দীর্ঘ তালিকা থেকে দেখতে পাচ্ছেন , এটি কেবলমাত্র GHC এর সাম্প্রতিক সংস্করণ নিয়ে কাজ করবে।

আমাদের টাইপ সিস্টেমের মধ্যে দৈর্ঘ্যের প্রতিনিধিত্ব করার একটি উপায় প্রয়োজন। সংজ্ঞা অনুসারে, একটি প্রাকৃতিক সংখ্যা হয় শূন্য ( Z) বা এটি অন্য কোনও প্রাকৃতিক সংখ্যার ( S n) এর উত্তরসূরি । সুতরাং, উদাহরণস্বরূপ, 3 নম্বর লেখা হবে S (S (S Z))

data Nat = Z | S Nat

সঙ্গে DataKinds এক্সটেনশন , এই dataঘোষণা একটি প্রবর্তন ধরনের বলা Natএবং দুই প্রকার কনস্ট্রাকটর নামক Sএবং Z- অন্য কথায় আমরা আছে টাইপ পর্যায়ের স্বাভাবিক সংখ্যার। নোট করুন যে প্রকারগুলি Sএবং Zকোনও সদস্যের মান নেই - কেবল প্রকারের ধরণের *মানগুলি বাস করে।

এখন আমরা একটি GADT পরিচিত দৈর্ঘ্য সহ ভেক্টর প্রতিনিধিত্ব করে। উল্লেখ্য ধরনের স্বাক্ষর: Vecএকটি টাইপ প্রয়োজন ধরনেরNat (যেমন একটি Zঅথবা একটি Sটাইপ) তার দৈর্ঘ্য প্রতিনিধিত্ব করতে।

data Vec :: Nat -> * -> * where
    VNil :: Vec Z a
    VCons :: a -> Vec n a -> Vec (S n) a
deriving instance (Show a) => Show (Vec n a)
deriving instance Functor (Vec n)
deriving instance Foldable (Vec n)
deriving instance Traversable (Vec n)

ভেক্টরগুলির সংজ্ঞা সংযুক্ত তালিকার সাথে মিল রয়েছে, এর দৈর্ঘ্য সম্পর্কে কিছু অতিরিক্ত টাইপ-স্তরের তথ্য রয়েছে। কোনও ভেক্টর হয় হয় VNil, এর ক্ষেত্রে এর দৈর্ঘ্য Z(এরো) হয়, বা এটি এমন একটি VConsঘর যা অন্য ভেক্টরের সাথে একটি আইটেম যুক্ত করে, এক্ষেত্রে এর দৈর্ঘ্য অন্যান্য ভেক্টর ( S n) এর চেয়ে আরও একটি বেশি । মনে রাখবেন যে কোনও ধরণের নির্মাণকারীর যুক্তি নেই n। দৈর্ঘ্যগুলি ট্র্যাক করার জন্য এটি কেবল সংকলনের সময়ে ব্যবহৃত হয়েছিল এবং সংকলক মেশিন কোড উত্পন্ন করার আগে মুছে ফেলা হবে।

আমরা একটি ভেক্টর টাইপ সংজ্ঞায়িত করেছি যা এর দৈর্ঘ্যের স্থির জ্ঞানের চারপাশে বহন করে। Vecতারা কীভাবে কাজ করে তার জন্য অনুভূতি পেতে কয়েকজনের প্রকারের জিজ্ঞাসা করা যাক :

ghci> :t (VCons 'a' (VCons 'b' VNil))
(VCons 'a' (VCons 'b' VNil)) :: Vec ('S ('S 'Z)) Char  -- (S (S Z)) means 2
ghci> :t (VCons 13 (VCons 11 (VCons 3 VNil)))
(VCons 13 (VCons 11 (VCons 3 VNil))) :: Num a => Vec ('S ('S ('S 'Z))) a  -- (S (S (S Z))) means 3

বিন্দুর পণ্যটি কেবল তালিকার জন্য যেমন এগিয়ে যায়:

-- note that the two Vec arguments are declared to have the same length
vap :: Vec n (a -> b) -> Vec n a -> Vec n b
vap VNil VNil = VNil
vap (VCons f fs) (VCons x xs) = VCons (f x) (vap fs xs)

zipWith :: (a -> b -> c) -> Vec n a -> Vec n b -> Vec n c
zipWith f xs ys = fmap f xs `vap` ys

dot :: Num a => Vec n a -> Vec n a -> a
dot xs ys = foldr (+) 0 $ zipWith (*) xs ys

vap, যা 'জিপ্লি' আর্গুমেন্টের ভেক্টরকে ফাংশনগুলির একটি ভেক্টর প্রয়োগ করে, এটি Vecপ্রয়োগকারী <*>; আমি এটি একটি রাখা হয়নিApplicative নজরে রাখিনি কারণ এটি অগোছালো হয়ে যায় । এছাড়াও নোট করুন যে আমি foldrসংকলক-উত্পন্ন উদাহরণ থেকে ব্যবহার করছি Foldable

আসুন এটি ব্যবহার করে দেখুন:

ghci> let v1 = VCons 2 (VCons 1 VNil)
ghci> let v2 = VCons 4 (VCons 5 VNil)
ghci> v1 `dot` v2
13
ghci> let v3 = VCons 8 (VCons 6 (VCons 1 VNil))
ghci> v1 `dot` v3
<interactive>:20:10:
    Couldn't match type ‘'S 'Z’ with ‘'Z’
    Expected type: Vec ('S ('S 'Z)) a
      Actual type: Vec ('S ('S ('S 'Z))) a
    In the second argument of ‘dot’, namely ‘v3’
    In the expression: v1 `dot` v3

গ্রেট! আপনি যখন dotভেক্টরগুলির দৈর্ঘ্য মেলে না তার চেষ্টা করার সময় আপনি একটি সংকলন-সময় ত্রুটি পান ।


ভেক্টরগুলিকে একসাথে জড়িত করার জন্য একটি অনুষ্ঠানে এই চেষ্টা করা হয়েছে:

-- This won't compile because the type checker can't deduce the length of the returned vector
-- VNil +++ ys = ys
-- (VCons x xs) +++ ys = VCons x (concat xs ys)

আউটপুট ভেক্টরের দৈর্ঘ্য দুটি ইনপুট ভেক্টরের দৈর্ঘ্যের যোগফল হবে । আমাদের কীভাবে Natএকসাথে যুক্ত করতে হয় তা টাইপ পরীক্ষককে শেখাতে হবে । এর জন্য আমরা একটি টাইপ-স্তরের ফাংশন ব্যবহার করি :

type family (n :: Nat) :+: (m :: Nat) :: Nat where
    Z :+: m = m
    (S n) :+: m = S (n :+: m)

এই type familyঘোষণাটি প্রকারভেদে ডাকে একটি ফাংশন প্রবর্তন করে:+: - অন্য কথায়, এটি টাইপ চেকারের পক্ষে দুটি প্রাকৃতিক সংখ্যার যোগফল গণনা করার জন্য একটি রেসিপি। এটি পুনরাবৃত্তভাবে সংজ্ঞায়িত করা হয় - যখনই বাম অপারেণ্ড Zএরোর চেয়ে বড় হয় আমরা আউটপুটে একটি যুক্ত করি এবং এটি পুনরাবৃত্তির কলগুলিতে একে একে হ্রাস করি। (টাইপ ফাংশনটি লিখতে এটি একটি ভাল অনুশীলন যা দুটি Natগুলিকে বহুগুণ করে )) এখন আমরা +++সংকলন করতে পারি :

infixr 5 +++
(+++) :: Vec n a -> Vec m a -> Vec (n :+: m) a
VNil +++ ys = ys
(VCons x xs) +++ ys = VCons x (concat xs ys)

আপনি এটি কীভাবে ব্যবহার করবেন তা এখানে:

ghci> VCons 1 (VCons 2 VNil) +++ VCons 3 (VCons 4 VNil)
VCons 1 (VCons 2 (VCons 3 (VCons 4 VNil)))

এখন পর্যন্ত এত সহজ। আমরা যখন যুক্তিযুক্তির বিপরীত কাজ করতে এবং একটি ভেক্টরকে দুটিতে বিভক্ত করতে চাই তখন কী হবে? আউটপুট ভেক্টরগুলির দৈর্ঘ্য আর্গুমেন্টের রানটাইম মানের উপর নির্ভর করে। আমরা এরকম কিছু লিখতে চাই:

-- this won't work because there aren't any values of type `S` and `Z`
-- split :: (n :: Nat) -> Vec (n :+: m) a -> (Vec n a, Vec m a)

কিন্তু দুর্ভাগ্যক্রমে হাস্কেল আমাদের তা করতে দেয় না। অনুমতি মান এর nযুক্তি প্রদর্শিত করতে রিটার্ন টাইপ (এই সাধারণত একটি বলা হয় নির্ভরশীল ফাংশন বা Pi টাইপ ,) "পুরো বর্ণালী" নির্ভরশীল ধরনের প্রয়োজন হবে যেহেতু DataKindsআমাদের টাইপ কনস্ট্রাকটর উন্নীত দেয়। এটি অন্য উপায়ে রাখতে, টাইপ কনস্ট্রাক্টর Sএবং Zমান স্তরে উপস্থিত হয় না। একটি নির্দিষ্ট সময়ের জন্য রান-টাইম উপস্থাপনের জন্য আমাদের সিঙ্গলটন মানগুলির নিষ্পত্তি করতে হবে Nat*

data Natty (n :: Nat) where
    Zy :: Natty Z  -- pronounced 'zed-y'
    Sy :: Natty n -> Natty (S n)  -- pronounced 'ess-y'
deriving instance Show (Natty n)

প্রদত্ত প্রকারের জন্য n(ধরণের সহ Nat), ধরণের এক ধরণের অবিকল থাকে Natty n। আমরা সিঙ্গলটন মানটি রান-টাইম সাক্ষী হিসাবে ব্যবহার করতে পারি n: একটি সম্পর্কে শিখতে Nattyআমাদের এর nবিপরীতটি শিখায় ।

split :: Natty n ->
         Vec (n :+: m) a ->  -- the input Vec has to be at least as long as the input Natty
         (Vec n a, Vec m a)
split Zy xs = (Nil, xs)
split (Sy n) (Cons x xs) = let (ys, zs) = split n xs
                           in (Cons x ys, zs)

এটি একটি স্পিন জন্য নেওয়া যাক:

ghci> split (Sy (Sy Zy)) (VCons 1 (VCons 2 (VCons 3 VNil)))
(VCons 1 (VCons 2 VNil), VCons 3 VNil)
ghci> split (Sy (Sy Zy)) (VCons 3 VNil)
<interactive>:116:21:
    Couldn't match type ‘'S ('Z :+: m)’ with ‘'Z’
    Expected type: Vec ('S ('S 'Z) :+: m) a
      Actual type: Vec ('S 'Z) a
    Relevant bindings include
      it :: (Vec ('S ('S 'Z)) a, Vec m a) (bound at <interactive>:116:1)
    In the second argument of ‘split’, namely ‘(VCons 3 VNil)’
    In the expression: split (Sy (Sy Zy)) (VCons 3 VNil)

প্রথম উদাহরণে, আমরা সফলভাবে একটি ত্রি-উপাদান ভেক্টর 2 পজিশনে বিভক্ত করেছি; তারপরে আমরা শেষের অবস্থানে কোনও ভেক্টরকে বিভক্ত করার চেষ্টা করার সময় আমরা একটি টাইপ ত্রুটি পেয়েছি। সিঙ্গলেটগুলি হ্যাস্কেলের কোনও মানের উপর নির্ভর করে একটি প্রকার তৈরির জন্য মানক কৌশল।

* singletonsলাইব্রেরিতেNatty আপনার মতো সিঙ্গলটন মান উত্পন্ন করতে কিছু টেম্পলেট হাস্কেল সহায়ক রয়েছে ।


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

data AVec a = forall n. AVec (Natty n) (Vec n a)
deriving instance (Show a) => Show (AVec a)

fromList :: [a] -> AVec a
fromList = Prelude.foldr cons nil
    where cons x (AVec n xs) = AVec (Sy n) (VCons x xs)
          nil = AVec Zy VNil

AVecএকটি অস্তিত্বমূলক প্রকার : টাইপ ভেরিয়েবল ডেটা কনস্ট্রাক্টরের nরিটার্ন টাইপের ক্ষেত্রে উপস্থিত হয় না AVec। আমরা এটি নির্ভরশীল জুটির অনুকরণের জন্য ব্যবহার করছি : fromListআপনাকে ভেক্টরের দৈর্ঘ্য স্থিতিশীলভাবে বলতে পারি না, তবে এটি ভ্যাক্টরের দৈর্ঘ্য শিখতে প্যাটার্ন-ম্যাচ করে এমন কিছু ফিরিয়ে দিতে পারে - Natty nটিউপলের প্রথম উপাদানটিতে । যেমন কনর ম্যাকব্রাইড এটিকে সম্পর্কিত উত্তরে রাখে , "আপনি এক জিনিস তাকান, এবং তাই করছেন, অন্য বিষয়ে জানার"।

এটি অস্তিত্বযুক্ত পরিমাণযুক্ত প্রকারের জন্য একটি সাধারণ কৌশল। যেহেতু আপনি এমন ডেটা দিয়ে আসলে কিছুই করতে পারবেন না যার জন্য আপনি টাইপটি জানেন না - একটি ফাংশন লেখার চেষ্টা করুন data Something = forall a. Sth a- অস্তিত্বগুলি প্রায়শই জিএডিডি প্রমাণ সহ বান্ডিল হয়ে আসে যা আপনাকে প্যাটার্ন-ম্যাচিং টেস্টগুলি সম্পাদন করে মূল ধরণের পুনরুদ্ধার করতে দেয়। অস্তিত্বের জন্য অন্যান্য সাধারণ নিদর্শনগুলির মধ্যে রয়েছে আপনার প্রকার ( data AWayToGetTo b = forall a. HeresHow a (a -> b)) প্রসেস করার জন্য প্যাকেজিং ফাংশনগুলি অন্তর্ভুক্ত যা প্রথম শ্রেণীর মডিউলগুলি করার একটি ঝরঝরে উপায়, বা বিল্ড-ইন একটি ধরণের শ্রেণীর অভিধান ( data AnOrd = forall a. Ord a => AnOrd a) যা উপ -টাইপ পলিমারফিজম অনুকরণ করতে সহায়তা করতে পারে।

ghci> fromList [1,2,3]
AVec (Sy (Sy (Sy Zy))) (VCons 1 (VCons 2 (VCons 3 Nil)))

নির্ভরশীল জুড়ি দরকারী যখনই তথ্য স্থির বৈশিষ্ট্য গতিশীল তথ্যের উপর নির্ভর করে সংকলন সময়ে উপলব্ধ না। এখানে filterভেক্টরদের জন্য:

filter :: (a -> Bool) -> Vec n a -> AVec a
filter f = foldr (\x (AVec n xs) -> if f x
                                    then AVec (Sy n) (VCons x xs)
                                    else AVec n xs) (AVec Zy VNil) 

করতে dotদুই AVecগুলি, আমরা GHC প্রমাণ করতে যে তাদের লেন্থ সমান প্রয়োজন। Data.Type.Equalityএকটি GADT সংজ্ঞা দেয় যা কেবল তখনই তৈরি করা যায় যখন এর ধরণের আর্গুমেন্টগুলি একই হয়:

data (a :: k) :~: (b :: k) where
    Refl :: a :~: a  -- short for 'reflexivity'

আপনি যখন প্যাটার্ন-ম্যাচ চালু করেন Refl, জিএইচসি তা জানে a ~ b। আপনাকে এই ধরণের সাথে কাজ করতে সহায়তা করার জন্য কয়েকটি ফাংশন রয়েছে: আমরা gcastWithসমতুল্য ধরণের মধ্যে রূপান্তর TestEqualityকরতে এবং দুটি Nattyসমান কিনা তা নির্ধারণ করার জন্য ব্যবহার করব ।

দুই সমতা পরীক্ষা করার জন্য Nattyগুলি, আমরা সত্য যে যদি দুটি সংখ্যার সমান হয়, তখন তাদের উত্তরাধিকারী এছাড়াও সমান হয় করতে ব্যবহার করতে হবে যাচ্ছেন ( :~:হয় সর্বসম উপর S):

congSuc :: (n :~: m) -> (S n :~: S m)
congSuc Refl = Refl

Reflবাম-পাশের প্যাটার্নের মিলটি জিএইচসিকে এটি জানতে দেয় n ~ m। সেই জ্ঞানের সাথে, এটি তুচ্ছ S n ~ S m, সুতরাং জিএইচসি আমাদের একটি নতুন ফিরিয়ে দিতে দেয়Refl ফিরিয়ে দিতে দেয়।

এখন আমরা TestEqualityপ্রত্যক্ষ পুনরাবৃত্তি দ্বারা একটি উদাহরণ লিখতে পারেন । উভয় সংখ্যা শূন্য হলে তারা সমান। যদি উভয় সংখ্যার পূর্বসূরি থাকে তবে পূর্বসূরীরা সমান হলে তারা সমান। (যদি তারা সমান না হয় তবে কেবল ফিরে আসুন Nothing))

instance TestEquality Natty where
    -- testEquality :: Natty n -> Natty m -> Maybe (n :~: m)
    testEquality Zy Zy = Just Refl
    testEquality (Sy n) (Sy m) = fmap congSuc (testEquality n m)  -- check whether the predecessors are equal, then make use of congruence
    testEquality Zy _ = Nothing
    testEquality _ Zy = Nothing

এখন আমরা টুকরাগুলি dotএক জোড়া AVecঅজানা দৈর্ঘ্যের এক সাথে রাখতে পারি।

dot' :: Num a => AVec a -> AVec a -> Maybe a
dot' (AVec n u) (AVec m v) = fmap (\proof -> gcastWith proof (dot u v)) (testEquality n m)

প্রথমে AVecভেক্টরগুলির দৈর্ঘ্যের একটি রানটাইম উপস্থাপনাটি বের করতে কনস্ট্রাক্টরের প্যাটার্ন ম্যাচ । এখন testEqualityসেই দৈর্ঘ্য সমান কিনা তা নির্ধারণ করতে ব্যবহার করুন । তারা যদি হয় তবে আমাদের থাকবে Just Refl; তার সামঞ্জস্য অনুমানটি স্রাব করে ভাল-টাইপ করা gcastWithহয়েছে তা নিশ্চিত করার জন্য সেই সাম্যতার প্রমাণ ব্যবহার করবে ।dot u vn ~ m

ghci> let v1 = fromList [1,2,3]
ghci> let v2 = fromList [4,5,6]
ghci> let v3 = fromList [7,8]
ghci> dot' v1 v2
Just 32
ghci> dot' v1 v3
Nothing  -- they weren't the same length

দ্রষ্টব্য, যেহেতু কোনও দৈর্ঘ্যের স্থির জ্ঞান ছাড়াই ভেক্টর মূলত একটি তালিকা, তাই আমরা কার্যকরভাবে এর তালিকা সংস্করণটি পুনরায় প্রয়োগ করেছি dot :: Num a => [a] -> [a] -> Maybe a। পার্থক্যটি হ'ল এই সংস্করণটি ভেক্টরদের ক্ষেত্রে প্রয়োগ করা হয়েছে dot। এখানে বিন্দু: সামনে টাইপ পরীক্ষক আপনাকে কল করার অনুমতি দেবে dot, তোমাদের যাচাই করেছি আবশ্যক কিনা ইনপুট তালিকা একই দৈর্ঘ্য ব্যবহার আছে testEquality। আমি ifস্টেস্টেমগুলি ভুল উপায়ে পেয়ে যাওয়ার ঝুঁকিপূর্ণ , কিন্তু নির্ভরশীল টাইপযুক্ত সেটিংয়ে নেই!

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

যেহেতু Nothingখুব তথ্যবহুল নয়, আপনি ব্যর্থতার ক্ষেত্রে দৈর্ঘ্য সমান নয় (প্রমাণ আকারে তাদের পার্থক্য 0 নয়) প্রমাণটিdot' ফেরতের প্রকারটি আরও সংশোধন করতে পারেন । এটি সম্ভবত কোনও ত্রুটি বার্তা ফেরত দেওয়ার জন্য স্ট্যান্ডার্ড হাস্কেল প্রযুক্তির সাথে একই রকম , যদিও একটি স্ট্রিংয়ের চেয়ে প্রুফ টার্মটি আরও বেশি গণনামূলকভাবে কার্যকর!Either String a


নির্ভরশীল-টাইপড হাস্কেল প্রোগ্রামিংয়ে প্রচলিত কিছু কৌশলগুলির এই হুইসল-স্টপ ট্যুরটি শেষ হয়। হাস্কেলের মধ্যে এই জাতীয় প্রকারের সাথে প্রোগ্রামিং করা সত্যিই দুর্দান্ত তবে একই সময়ে সত্যই বিশ্রী। - উপস্থাপনা যা একই জিনিস মানে প্রচুর মধ্যে আপনার সমস্ত নির্ভরশীল ডেটা ব্রেকিং Natধরন, Natধরনের, Natty nSingleton - boilerplate, সাহায্য করার জন্য কোড-জেনারেটর অস্তিত্ব সত্ত্বেও, বেশ কষ্টকর সত্যিই হয়। প্রকার স্তরে কী প্রচার করা যায় সে সম্পর্কে বর্তমানে সীমাবদ্ধতা রয়েছে। এটা যদিও tantalizing! সম্ভাবনাগুলিতে মন বিচলিত হয় - সাহিত্যে দৃ strongly়ভাবে টাইপ করা printf, ডাটাবেস ইন্টারফেস, ইউআই লেআউট ইঞ্জিনগুলির হ্যাস্কেলের উদাহরণ রয়েছে ...

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


@ বেঞ্জামিন এফওয়াইআই, ইদ্রিস লিঙ্কটি শেষে ভাঙ্গা মনে হচ্ছে।
এরিক tদ

@ এরিকইডট উফ, এটি নির্দেশ করার জন্য ধন্যবাদ! আমি এটি আপডেট করব।
বেনিয়ামিন হডসন

14

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


এটি নির্ভরযোগ্য টাইপিং মোটেই নয়। নির্ভরশীল টাইপিং রান টাইমে টাইপ সম্পর্কে কথা বলে তবে টাইপের মধ্যে বেকিং ডাইমেনিয়ালিটি সহজেই সংকলন-সময়ে করা যায়।
ডেড এমএমজি

4
@ ডিডএমজি বিপরীতে, নির্ভরশীল টাইপিং সংকলন সময়ে মানগুলি সম্পর্কে কথা বলে । প্রকারভেদরান সময় প্রতিফলন, না নির্ভরশীল টাইপ করছে। আপনি আমার উত্তর থেকে দেখতে পাচ্ছেন, প্রকারের মধ্যে বেকিং মাত্রিকতা কোনও সাধারণ মাত্রার পক্ষে খুব সহজ for (আপনি সংজ্ঞায়িত করতে পারেন , এবং আরও অনেক কিছু কিন্তু প্রশ্নটি যা জিজ্ঞাসা করে তা নয়))newtype Vec2 a = V2 (a,a)newtype Vec3 a = V3 (a,a,a)
বেঞ্জামিন হজসন

ঠিক আছে, মানগুলি কেবল রানটাইমের সময় উপস্থিত হয়, তাই আপনি সংকলন-সময়ে মানগুলি সম্পর্কে সত্যই কথা বলতে পারবেন না আপনি যদি না হ্যালটিং সমস্যা সমাধান করতে চান। আমি যা বলছি তা হ'ল এমনকি সি ++ তে আপনি মাত্রিক মাত্রায় টেমপ্লেট করতে পারেন এবং এটি দুর্দান্ত কাজ করে। হাস্কেলের মধ্যে কি এর সমতুল্য নেই?
ডেড এমএমজি

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

4
@ বেঞ্জামিনহডসন আপনি টেমপ্লেটগুলি সহ নির্ভরশীল প্রকারগুলি করতে পারবেন না কারণ আপনি পাই টাইপের অনুকরণ করতে পারবেন না। "ক্যাননিকাল" নির্ভরশীল টাইপ দাবি করবে আবশ্যক আপনি প্রয়োজন Pi (x : A). Bথেকে একটি ফাংশন যা Aকরতে B xযেখানে xফাংশনের যুক্তি। এখানে আর্গুমেন্ট হিসাবে সরবরাহ করা এক্সপ্রেশনটির উপর ফাংশনের নির্ভরতাগুলির রিটার্ন টাইপ । যাইহোক, এই
সমস্তগুলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.