ডেটাতে অযৌক্তিক ফাংশনটি কী? কার্যকর নয়?


97

absurdফাংশন Data.Voidনিম্নলিখিত স্বাক্ষর, যেখানে রয়েছে Voidকথাটি জনবসতিহীন যে ধরনের প্যাকেজ দ্বারা রপ্তানি করা হয়:

-- | Since 'Void' values logically don't exist, this witnesses the logical
-- reasoning tool of \"ex falso quodlibet\".
absurd :: Void -> a

আমি যথেষ্ট যুক্তি জানি ডকুমেন্টেশন বক্তব্যের পেতে কি যে এই অনুরূপ, প্রস্তাবের হিসাবে ধরনের সাদৃশ্য দ্বারা, বৈধ সূত্রে ⊥ → a

আমি যে বিষয়টি নিয়ে হতবাক এবং কৌতূহলী তা হ'ল: এই প্রোগ্রামটি কোন ধরণের ব্যবহারিক প্রোগ্রামিং সমস্যায় কার্যকর? আমি ভাবছি যে সম্ভবত কিছু ক্ষেত্রে এটি "টাইপস-সেফ" কে পুরোপুরি হ্যান্ডেল করার "টাইপস-সেফ" উপায় হিসাবে কার্যকর "কেস হতে পারে না" কেস হিসাবে ব্যবহার করা যায়, তবে কারি-হাওয়ার্ডের ব্যবহারিক ব্যবহার সম্পর্কে আমি যথেষ্ট জানি না যে এই ধারণাটি রয়েছে কিনা তা জানাতে ঠিক ট্র্যাক।

সম্পাদনা: হাস্কেলের ক্ষেত্রে উদাহরণগুলি, তবে কেউ যদি নির্ভর করে টাইপ করা ভাষা ব্যবহার করতে চায় তবে আমি অভিযোগ করব না ...


5
একটি দ্রুত অনুসন্ধান অনুষ্ঠান absurdফাংশন সঙ্গে এই নিবন্ধটি ডিলিং ব্যবহার করা হয়েছে Contএকসংখ্যা: haskellforall.com/2012/12/the-continuation-monad.html
Artyom

6
আপনি এবং absurdএর মধ্যে আইসোমরফিজমের একটি দিক হিসাবে দেখতে পারেন । Voidforall a. a
ড্যানিয়েল ওয়াগনার

উত্তর:


61

জীবন কিছুটা কঠিন, যেহেতু হাস্কেল অ-কঠোর। সাধারণ ব্যবহারের ক্ষেত্রে অসম্ভব পথগুলি পরিচালনা করা। উদাহরণ স্বরূপ

simple :: Either Void a -> a
simple (Left x) = absurd x
simple (Right y) = y

এটি কিছুটা কার্যকর হতে দেখা যাচ্ছে। এর জন্য একটি সহজ ধরণের বিবেচনা করুনPipes

data Pipe a b r
  = Pure r
  | Await (a -> Pipe a b r)
  | Yield !b (Pipe a b r)

এটি গ্যাব্রিয়েল গনজালেসের Pipesলাইব্রেরি থেকে স্ট্যান্ডার্ড পাইপ ধরণের একটি কঠোর-আইয়েড এবং সরলিকৃত সংস্করণ । এখন, আমরা এমন পাইপটি এনকোড করতে পারি যা কখনই ফলন দেয় না (যেমন, গ্রাহক)

type Consumer a r = Pipe a Void r

এটি সত্যিই কখনও ফলন দেয় না। এই ইঙ্গিত করে যে একটি সঠিক ভাঁজ নিয়ম Consumerহল

foldConsumer :: (r -> s) -> ((a -> s) -> s) -> Consumer a r -> s
foldConsumer onPure onAwait p 
 = case p of
     Pure x -> onPure x
     Await f -> onAwait $ \x -> foldConsumer onPure onAwait (f x)
     Yield x _ -> absurd x

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

সম্ভবত সবচেয়ে ক্লাসিক ব্যবহার Voidহল সিপিএসে।

type Continuation a = a -> Void

যে, একটি Continuationএকটি ফাংশন যা কখনও ফিরে না। Continuation"নয়" টাইপের সংস্করণ। এটি থেকে আমরা সিপিএসের একটি মোনাদ পাই (শাস্ত্রীয় যুক্তির সাথে মিল রেখে)

newtype CPS a = Continuation (Continuation a)

যেহেতু হাস্কেল খাঁটি, আমরা এই ধরণের বাইরে কিছুই পেতে পারি না।


4
হু, আমি আসলে সেই সিপিএস বিটটি অনুসরণ করতে পারি। আমি অবশ্যই আগে কারি-হাওয়ার্ডের দ্বিগুণ অস্বীকার / সিপিএসের চিঠিপত্রের কথা শুনেছি, তবে এটি বুঝতে পারি নি; আমি দাবি করতে যাচ্ছি না আমি এখন এটি পুরোপুরি পেয়েছি, তবে এটি অবশ্যই সহায়তা করে!
লুইস ক্যাসিলাস

5
@ এরিক অলিক, কঠোর ভাষায়, Voidজনবসতিহীন। হাস্কেলের মধ্যে এটি রয়েছে _|_। কঠোর ভাষায়, কোনও ডেটা কনস্ট্রাক্টর যিনি টাইপের আর্গুমেন্ট Voidনেন তা কখনই প্রয়োগ করা যায় না, তাই প্যাটার্ন মিলের ডান হাতটি অ্যাক্সেসযোগ্য। হাসকেলে, আপনাকে !এটি প্রয়োগের জন্য একটি ব্যবহার করতে হবে এবং জিএইচসি সম্ভবত লক্ষ্য করবে না যে পথটি অ্যাক্সেসযোগ্য।
dfeuer

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

4
@ জ্যাকাল্জ ইঙ্গিত: আর্গুমেন্টে পাস করার জন্য কোনও কিছু অনুসন্ধানের পরিবর্তে টাইপ a -> Voidএবং ফাংশনের ধরন নির্ধারণ করতে এটি ব্যবহার করুন (a -> Void) -> Void
পাইরুলেজ

4
@ পাইরুলেজ ধন্যবাদ! উত্তরটি পূর্ববর্তী ক্ষেত্রে এতটা সুস্পষ্ট বলে মনে হচ্ছে যে আমি কেন আগে এটি মিস করেছি তা আমি দেখতে পাচ্ছি না।
jcalz

57

লাম্বদা শর্তাদি তাদের বিনামূল্যে ভেরিয়েবলগুলি দ্বারা প্যারাম্যাট্রাইজ করার জন্য এই উপস্থাপনাটি বিবেচনা করুন। (বেলগার্ডি এবং হুক ১৯৯৪, বার্ড অ্যান্ড পেটারসন ১৯৯৯, আলটেনকির্চ এবং রেইস ১৯৯৯ এর কাগজপত্র দেখুন See)

data Tm a  = Var a
           | Tm a :$ Tm a
           | Lam (Tm (Maybe a))

Functorনাম পরিবর্তন Monadকরার ধারণাকে ক্যাপচার করে এবং প্রতিস্থাপনের ধারণাটি ক্যাপচার করে আপনি অবশ্যই এটি তৈরি করতে পারেন ।

instance Functor Tm where
  fmap rho (Var a)   = Var (rho a)
  fmap rho (f :$ s)  = fmap rho f :$ fmap rho s
  fmap rho (Lam t)   = Lam (fmap (fmap rho) t)

instance Monad Tm where
  return = Var
  Var a     >>= sig  = sig a
  (f :$ s)  >>= sig  = (f >>= sig) :$ (s >>= sig)
  Lam t     >>= sig  = Lam (t >>= maybe (Var Nothing) (fmap Just . sig))

এখন বন্ধ শব্দগুলি বিবেচনা করুন : এগুলির বাসিন্দারা Tm Void। আপনার ইচ্ছামত মুক্ত ভেরিয়েবলগুলির সাথে শর্তাবলী বদ্ধ শর্তাদি এম্বেড করতে সক্ষম হওয়া উচিত। কীভাবে?

fmap absurd :: Tm Void -> Tm a

অবশ্যই ধরা পড়ে যে এই ফাংশনটি সঠিকভাবে কিছুই না করে শব্দটিকে অতিক্রম করবে। তবে এটি তার চেয়েও বেশি সততার স্পর্শ unsafeCoerce। এবং এজন্যই এতে vacuousযুক্ত করা হয়েছিল Data.Void...

অথবা একটি মূল্যায়নকারী লিখুন। এখানে মুক্ত ভেরিয়েবল সহ মান রয়েছে b

data Val b
  =  b :$$ [Val b]                              -- a stuck application
  |  forall a. LV (a -> Val b) (Tm (Maybe a))   -- we have an incomplete environment

আমি সবেমাত্র ল্যাম্বডাসকে ক্লোজার হিসাবে উপস্থাপন করেছি। মূল্যায়ন aওভার মানগুলিতে ফ্রি ভেরিয়েবল ম্যাপিং দ্বারা পরিবেশক প্যারামেট্রাইজড হয় b

eval :: (a -> Val b) -> Tm a -> Val b
eval g (Var a)   = g a
eval g (f :$ s)  = eval g f $$ eval g s where
  (b :$$ vs)  $$ v  = b :$$ (vs ++ [v])         -- stuck application gets longer
  LV g t      $$ v  = eval (maybe v g) t        -- an applied lambda gets unstuck
eval g (Lam t)   = LV g t

তুমি এটা অনুধাবন কর. যে কোনও টার্গেটে একটি বদ্ধ শব্দটি মূল্যায়ন করা

eval absurd :: Tm Void -> Val b

সাধারণভাবে, Voidখুব কমই এটি নিজস্বভাবে ব্যবহৃত হয়, তবে আপনি যখন কোনও প্রকারের প্যারামিটারটি এমনভাবে ইনস্ট্যান্ট করতে চান যা কোনও ধরণের অসম্ভবকে নির্দেশ করে (উদাহরণস্বরূপ, এখানে একটি বদ্ধ মেয়াদে একটি মুক্ত ভেরিয়েবল ব্যবহার করে)। প্রায়শই এই parametrized ধরনের উচ্চতর-অর্ডার ফাংশন অপারেশন পুরো ধরনের উপর পরামিতি উপর অপারেশন তুলে সঙ্গে আসা (যেমন, এখানে, fmap, >>=, eval)। সুতরাং আপনি absurdসাধারণ উদ্দেশ্যে অপারেশন হিসাবে পাস Void

অন্য উদাহরণের জন্য, Either e vগণনাগুলি ক্যাপচার করার জন্য কল্পনা করুন যা আশাকরি আপনাকে একটি দেয় vতবে এটির ব্যতিক্রম বাড়াতে পারে e। আপনি এই পদ্ধতিটি খারাপ আচরণের ঝুঁকি দলিল হিসাবে অভিন্নভাবে ব্যবহার করতে পারেন। এই সেটিংটিতে নিখুঁতভাবে আচরণ করা গণনার eজন্য হতে হবে Void, তারপরে ব্যবহার করুন

either absurd id :: Either Void v -> v

নিরাপদে চালানো বা

either absurd Right :: Either Void v -> Either e v

অনিরাপদ বিশ্বে নিরাপদ উপাদান এম্বেড করতে।

ওহ, এবং একটি শেষ হররে, একটি "ঘটতে পারে না" পরিচালনা করে। এটি জেনেরিক জিপার নির্মাণে প্রদর্শিত হয়, যেখানেই কার্সার হতে পারে না।

class Differentiable f where
  type D f :: * -> *              -- an f with a hole
  plug :: (D f x, x) -> f x       -- plugging a child in the hole

newtype K a     x  = K a          -- no children, just a label
newtype I       x  = I x          -- one child
data (f :+: g)  x  = L (f x)      -- choice
                   | R (g x)
data (f :*: g)  x  = f x :&: g x  -- pairing

instance Differentiable (K a) where
  type D (K a) = K Void           -- no children, so no way to make a hole
  plug (K v, x) = absurd v        -- can't reinvent the label, so deny the hole!

আমি সিদ্ধান্ত নিলাম বাকীটি মুছে ফেলবেন না, যদিও এটি একেবারেই প্রাসঙ্গিক নয়।

instance Differentiable I where
  type D I = K ()
  plug (K (), x) = I x

instance (Differentiable f, Differentiable g) => Differentiable (f :+: g) where
  type D (f :+: g) = D f :+: D g
  plug (L df, x) = L (plug (df, x))
  plug (R dg, x) = R (plug (dg, x))

instance (Differentiable f, Differentiable g) => Differentiable (f :*: g) where
  type D (f :*: g) = (D f :*: g) :+: (f :*: D g)
  plug (L (df :&: g), x) = plug (df, x) :&: g
  plug (R (f :&: dg), x) = f :&: plug (dg, x)

আসলে, এটি প্রাসঙ্গিক হতে পারে। আপনি যদি দুঃসাহসী বোধ করেন তবে এই অসমাপ্ত নিবন্ধটি দেখায় যে কীভাবে Voidবিনামূল্যে ভেরিয়েবলগুলির সাথে শর্তগুলির উপস্থাপনা সংকুচিত করতে ব্যবহার করতে হয়

data Term f x = Var x | Con (f (Term f x))   -- the Free monad, yet again

কোনও সিন্ট্যাক্সে Differentiableএবং Traversableফান্টেক্টর থেকে অবাধে উত্পাদিত f। আমরা Term f Voidকোনও মুক্ত ভেরিয়েবলবিহীন অঞ্চলগুলির প্রতিনিধিত্ব করতে এবং কোনও বিচ্ছিন্ন মুক্ত ভেরিয়েবলের সাথে অঞ্চলগুলির মধ্য দিয়ে টিউব টানেলিং [D f (Term f Void)]উপস্থাপন করতে ব্যবহার করি , অথবা দুটি বা আরও বেশি মুক্ত ভেরিয়েবলের পথে একটি জংশন। অবশ্যই নিবন্ধটি শেষ করতে হবে।

কোনও মূল্য নেই এমন এক ধরণের জন্য (বা কমপক্ষে, ভদ্র সংস্থায় কথা বলার অপেক্ষা রাখে না), Voidউল্লেখযোগ্যভাবে কার্যকর। এবং absurdআপনি এটি ব্যবহার কিভাবে হয়।


চান forall f. vacuous f = unsafeCoerce fএকটি বৈধ GHC লেখা নিয়ম হতে পারে?
ক্যাকটাস

4
@ ক্যাকটাস, সত্যই নয়। বোগাস Functorদৃষ্টান্তগুলি জিএডিডি হতে পারে যা আসলে ফান্টেক্টারের মতো কিছু নয়।
dfeuer

তারা কি আইন Functorভঙ্গ করবে না fmap id = id? বা আপনি এখানে "বোগাস" বলতে যা বোঝাতে চাইছেন?
ক্যাকটাস

34

আমি ভাবছি যে সম্ভবত কিছু ক্ষেত্রে এটি "টাইপ করতে পারে না" ক্ষেত্রে সম্পূর্ণরূপে পরিচালনা করার টাইপ-নিরাপদ উপায় হিসাবে কার্যকর

এটা ঠিক ঠিক।

আপনি বলতে পারেন যে এর absurdচেয়ে বেশি কার্যকর নয় const (error "Impossible")। তবে এটি টাইপ সীমাবদ্ধ, যাতে এর একমাত্র ইনপুটটি টাইপের কিছু হতে পারে, এমন Voidএকটি ডেটা টাইপ যা ইচ্ছাকৃতভাবে জনশূন্য ছেড়ে যায়। এর অর্থ হ'ল এমন কোনও আসল মান নেই যা আপনি পাস করতে পারেন absurd। আপনি যদি কোনও কোডের কোনও শাখায় পৌঁছে যান যেখানে টাইপ চেকার মনে করেন যে আপনার কোনও প্রকারের অ্যাক্সেস রয়েছে Voidতবে ঠিক আছে, আপনি একটি উদাসীন পরিস্থিতিতে রয়েছেন । সুতরাং আপনি কেবলমাত্র absurdমূলত চিহ্নিত করতে ব্যবহার করেন যে কোডের এই শাখায় কখনও পৌঁছানো উচিত নয়।

"প্রাক্তন ফালসো কোডলিবিট" এর আক্ষরিক অর্থ "[ক] মিথ্যা [প্রস্তাব] থেকে, কিছু অনুসরণ করা"। সুতরাং যখন আপনি দেখতে পাচ্ছেন যে আপনি এমন একটি উপাত্ত রেখেছেন যার ধরণটি Void, আপনি জানেন যে আপনার হাতে মিথ্যা প্রমাণ রয়েছে। অতএব আপনি যে কোনও গর্ত (মাধ্যমে absurd) চান তা পূরণ করতে পারেন , কারণ একটি মিথ্যা প্রস্তাব থেকে, কিছু অনুসরণ করে।

কন্ডুইটের পিছনে থাকা ধারণাগুলি সম্পর্কে আমি একটি ব্লগ পোস্ট লিখেছিলাম যার ব্যবহারের উদাহরণ রয়েছে absurd

http://unmittedparallel.wordpress.com/2012/07/30/pines-to-condits-part-6-leftovers/#running-a-pipline


13

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

data RuleSet a            = Known !a | Unknown String
data GoRuleChoices        = Japanese | Chinese
type LinesOfActionChoices = Void
type GoRuleSet            = RuleSet GoRuleChoices
type LinesOfActionRuleSet = RuleSet LinesOfActionChoices

তারপরে আপনি এটির absurdমতো ব্যবহার করতে পারেন , উদাহরণস্বরূপ:

handleLOARules :: (String -> a) -> LinesOfActionsRuleSet -> a
handleLOARules f r = case r of
    Known   a -> absurd a
    Unknown s -> f s

13

খালি ডেটা প্রকারকে কীভাবে উপস্থাপন করা যায় তার বিভিন্ন উপায় রয়েছে । একটি হ'ল খালি বীজগণিত ডেটা টাইপ। আরেকটি উপায় হ'ল এটিকে একটি for. alias বা একটি উপাধি তৈরি করা

type Void' = forall a . a

হাস্কেল-এ আমরা এটিই সিস্টেম এফ এ এনকোড করতে পারি ( প্রুফ এবং প্রকারের 11 অনুচ্ছেদ দেখুন )। এই দুটি বিবরণ অবশ্যই আইসোমর্ফিক এবং আইসোমরফিজম দ্বারা \x -> x :: (forall a.a) -> Voidএবং এর সাক্ষী হয় absurd :: Void -> a

কিছু ক্ষেত্রে, আমরা সুস্পষ্ট রূপটি পছন্দ করি, সাধারণত যদি খালি ডেটা টাইপটি কোনও ফাংশনের যুক্তিতে বা আরও জটিল ডেটা টাইপ যেমন ডেটা.কন্ডুইটে প্রদর্শিত হয় :

type Sink i m r = Pipe i i Void () m r

কিছু ক্ষেত্রে, আমরা পলিমারফিক বৈকল্পিক পছন্দ করি, সাধারণত খালি ডেটা টাইপ কোনও ফাংশনের রিটার্ন টাইপের সাথে জড়িত।

absurd উত্থাপিত হয় যখন আমরা এই দুটি উপস্থাপনার মধ্যে রূপান্তর করি।


উদাহরণস্বরূপ, callcc :: ((a -> m b) -> m a) -> m aব্যবহার (অন্তর্ভুক্ত) forall b। এটি প্রকারের ((a -> m Void) -> m a) -> m aমতোও হতে পারে , কারণ মহাদেশটিতে কল আসলে ফিরে আসে না, এটি নিয়ন্ত্রণটি অন্য একটি পয়েন্টে স্থানান্তর করে। আমরা যদি ধারাবাহিকতা নিয়ে কাজ করতে চাই, আমরা সংজ্ঞা দিতে পারি

type Continuation r a = a -> Cont r Void

(আমরা ব্যবহার করতে পারি type Continuation' r a = forall b . a -> Cont r bতবে এর জন্য ২ ধরণের র‌্যাঙ্কের প্রয়োজন)) এবং তারপরে vacuousMএটিকে রূপান্তরিত Cont r Voidকরে Cont r b

(এছাড়াও মনে রাখবেন আপনি ব্যবহার করতে পারেন haskellers.com একটি নির্দিষ্ট প্যাকেজের ব্যবহার (রিভার্স নির্ভরতা) জন্য অনুসন্ধান করতে, কে এবং কিভাবে ব্যবহার দেখতে চান অকার্যকর প্যাকেজ।)


TypeApplicationsবিস্তারিত সম্পর্কে আরো স্পষ্ট হতে ব্যবহার করা যেতে পারে proof :: (forall a. a) -> Void: proof fls = fls @Void
আইসল্যান্ড_জ্যাক

1

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

উদাহরণস্বরূপ, এই ফাংশনটি তালিকা থেকে এমন কোনও উপাদানকে সরিয়ে দেয় যেখানে সেখানে উপস্থিত টাইপ-লেভেল ক্যারেন্টারেন্ট রয়েছে:

shrink : (xs : Vect (S n) a) -> Elem x xs -> Vect n a
shrink (x :: ys) Here = ys
shrink (y :: []) (There p) = absurd p
shrink (y :: (x :: xs)) (There p) = y :: shrink (x :: xs) p

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

কারি-হাওয়ার্ড পয়েন্ট অফ ভিউয়ের মাধ্যমে, যেখানে প্রস্তাবনা রয়েছে, তারপরে absurdদ্বন্দ্বের দ্বারা প্রমাণ হিসাবে কিউইডকে সাজানো হয়েছে।

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