ترجمة "لماذا تعتبر البرمجة الوظيفية مهمة" إلى لغة هاسكل

StackOverflow https://stackoverflow.com/questions/1000145

  •  05-07-2019
  •  | 
  •  

سؤال

من أجل الإثراء الثقافي والفكري، قررت أن أتعلم القليل من هاسكل.كنت أطالع هيوز "لماذا تعتبر البرمجة الوظيفية مهمة" وأحاول ترجمة الكود الخاص به إلى لغة هاسكل الحقيقية.لقد أرفقت بعضًا من محاولتي أدناه (بالنسبة للأجزاء الرقمية من الورقة؛تعد خوارزمية ألفا بيتا أكثر إثارة للاهتمام ولكن يجب علي أيضًا أن أكتب مُقيِّمًا للعبة من الصفر!).

في هذه المرحلة، كان الأمر مجرد تمرين في بناء جملة هاسكل أكثر من أي شيء آخر.لقد قمت بالفعل بأشياء بسيطة مثل الترجمة repeat في هاسكل الأصلية iterate, ، قم بترجمة بعض الوظائف التي تستخدم الكثير من الأقواس لتكوين الوظيفة (مما يجعلها خالية من النقاط في العملية)، وما إلى ذلك.

لكن الكود الخاص بي يعمل بالتأكيد، وأتساءل عما إذا كان "Haskell-ish" كافيًا.هل يمكن لأي خبراء أن يقدموا لي بعض التلميحات؟

-- 4.1 Newton-Raphson square roots
next n x = (x + n/x)/2.0

-- -- this is "iterate::(a->a)->a->[a]"
-- repeat f a  = a : iterate f (f a)

within eps (a:b:rest) = 
  if abs(a-b) <= eps 
    then b
    else within eps (b:rest)

sqroot a0 eps n = within eps (iterate (next n) a0)

relative eps (a:b:rest) = 
  if abs(a-b) <= eps*abs(b)
    then b
    else relative eps (b:rest)

relativesqrt a0 eps n = relative eps (iterate (next n) a0)

-- 4.2 numerical differentiation

easydiff f x h = (f (x+h) - f x) / h

differentiate h0 f x = map (easydiff f x) (iterate (/2) h0)

-- diff1a h0 eps f x = within eps (differentiate h0 f x)
diff1 h0 eps f = within eps . differentiate h0 f 

elimerror n (a:b:rest) = (b*(2**n)-a)/(2**n-1) : elimerror n (b:rest)

-- need fromIntegral to make a non-integer out of the Int which comes out of round
order (a:b:c:rest) =  fromIntegral (round (logBase 2 ((a-c)/(b-c)-1)))

improve s = elimerror (order s) s 

--diff2a h0 eps f x = within eps (improve (differentiate h0 f x))
diff2 h0 eps f = within eps . improve . differentiate h0 f 

--super s = map second (iterate improve s) -- how can we make this point-free?
super :: (RealFrac t, Floating t) => [t] -> [t] 
           -- w/o this it wants to be [double]->[double]
super = map second . iterate improve

-- second (a:b:rest) = b
second = head . tail

diff3 h0 eps f = within eps . super . differentiate h0 f

-- 4.3 integration

easyintegrate f a b = (f a + f b)*(b-a)/2

-- addpair becomes (uncurry (+))

integrate f a b = integ f a b (f a) (f b) 

integ f a b fa fb = 
  (fa+fb)*(b-a)/2 : map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))
  where m = (a+b)/2 
        fm = f m 

-- test: following should be about pi
approxpi eps = within eps (improve (integrate (\x -> 4/(1+x*x)) 0 1))
superpi eps = within eps (super (integrate (\x -> 4/(1+x*x)) 0 1))

-- is there any way to keep track of the number of iterations? state monad, but seems like a lot of work...\

لا يوجد حل صحيح

نصائح أخرى

4.1 جذور نيوتن-رافسون التربيعية

هذين الخطين

sqroot a0 eps n = within eps (iterate (next n) a0)
relativesqrt a0 eps n = relative eps (iterate (next n) a0)

متطابقتان تقريبًا، لذا يمكنك تجريد الأشياء خطوة أخرى إلى الأمام:

sqroot method a0 eps n = method eps (iterate (next n) a0)
relativesqrt = sqroot relative
withinsqrt   = sqroot within

4.2 التمايز العددي

أنا لا أرى الهدف من وجود h0 كحجة ل differentiate تعمل لأنها مجرد نقطة البداية لـ 0 تسلسل الحد.(وهذا ليس صحيحا بالنسبة ل a0 في حالة نيوتن-رابسون، حيث قد تكون نقطة البداية مهمة).

أعتقد أنه من المناسب أيضًا تجريد المعدل الذي يقترب فيه هذا الحد من الصفر:

differentiate rate f x = map (easydiff f x) (iterate rate 1)

بالطبع يمكن للمرء أن يفعل كلا الأمرين:

differentiate rate h0 f x = map (easydiff f x) (iterate rate h0)

على أية حال، فهو قرار تعسفي للغاية.

4.2 التكامل

يمكنك استخدام

zipWith (+) (integ f a m fa fm) (integ f m b fm fb)

بدلاً من

map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))

الذي أعتقد أنه أكثر قابلية للقراءة.

لwithin وrelative أود أن استخدام التدوين حراسة:

within eps (a:b:rest)
  | abs(a-b)<=eps = b
  | otherwise = within eps (b:rest)

لsecond، يمكن أن تكتب !! 1. خصوصا أن الأخير هو تفضيل شخصي، وأعتقد.

ويجب أيضا إعطاء التوقيعات نوع.

تعديل : إذا كنت في التشويش، في محاولة:

within :: (Ord a, Num a) => a -> [a] -> a
within eps l@(_:xs) = snd. head . filter ((<= eps) . fst) $ zip zs xs
   where
    zs = zipWith (\ a b -> abs (a-b)) l xs

و(نوع التحقق منها، لم تختبر - وأنا لا أعرف ما إذا كنت تحصل على حق مرشح أو إذا كان لابد من انتفى؛)

وقد كتب

وروجر كوستيلو ملخص قسمين من ورقة جون هيوز ترجمة رمز ميراندا الأصلي لهاسكل. هنا جزء واحد و <لأ href = "HTTP: // شبكة الاتصالات العالمية .xfront.com / هاسكل / لماذا-المسائل الوظيفية-برمجة-الجزء-2.pdf "يختلط =" نوفولو "> الجزء الثاني من writeup له.

وهكذا، وهذا هو مستقيم عبر الترجمة (أي، في محاولة للحفاظ على رمز وتبحث مماثلة قدر الإمكان) أو جزءا لا يتجزأ من (أي جعل العديد من القرص الاصطلاحية إلى رمز وقت ممكن، دون أن الأمثلة أكثر صرامة لفهم وبطبيعة الحال) واحد؟

وعلى افتراض أن هذا "المشروع" لا يزال مستمرا ......

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top