簡體   English   中英

用提升理解 Haskell lambda 表達式

[英]Understanding Haskell lambda expressions with lifting

我試圖理解清單 1中的代碼,它提升了基本數值運算以生成時變數字。 然后使用時變數來計算不同時間點之間的距離。 移動距離的計算“似乎”需要對一個Time參數應用幾個 lambda 函數。 我不確定允許將一個參數應用於距離計算的確切評估機制:

(dist mp1 mp2) 2.0 ( 1 )

我對 lambda 表達式和提升有一個基本的了解,但是我不明白他們在這段代碼中的組合。 任何對 ( 1 ) 的詳細評估的見解將不勝感激。

清單 1

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
module MovingPoint where
data Point a = Point { x ::a, y :: a } deriving Show
type Time = Double
type Moving v = Time -> v

-- Lifting functions
lift1 op a = \t -> op (a t)
lift2 op a b = \t -> op (a t) (b t)

class Number a where
 add, sub, mul :: a -> a -> a
 sqr, sqrt1 :: a -> a
 sqr a = a `mul` a -- default def 

-- define Number operations using builtin Num class
instance Number Double where
  add = (+)
  sub = (-)
  mul = (*)
  sqrt1 = sqrt

-- The calculation of the distance between two points
dist :: Number a => Point a -> Point a -> a
dist a b = sqrt1 (sqr((x a) `sub` (x b)) `add` sqr ((y a) `sub` (y b)))


-- Lift numbers. LHS ops are for (Moving Double), RHS ops are for Double
instance Number (Moving Double) where
 add = lift2 add
 sub = lift2 sub
 mul = lift2 mul
 sqrt1 = lift1 sqrt1
 sqr = lift1 sqr


mp1, mp2 :: Point (Moving Double)
mp1 = Point (\t -> (4.0 `add` (0.5 `mul` t))) (\t -> (4.0 `sub`  (0.5 `mul` t)))
mp2 = Point (\t -> (0.0 `add` (1.0 `mul` t))) (\t -> (0.0 `sub`  (1.0 `mul` t)))

--  distance between mp1 and mp2 at times 2.0 and 10.0
md1 = (dist mp1 mp2) 2.0 -- > 5.8
md2 = (dist mp1 mp2) 10.0 -- > 9.05

評論答案

我無法正確格式化評論,所以我在這里添加了它。 專注於sqr中的sub

sqrt1 (sqr((\t -> (4.0 + 0.5 * t)) sub (\t -> (0.0 + 1.0 * t)))...)

= 這個sub的 arguments 都是(Moving Double) ,所以使用中綴表示法使用 def (lift2 (op) ab = \t -> (at) op (bt))

sqrt1 (sqr(\t -> (4.0 + 0.5 * t) - (0.0 + 1.0 * t))...)

我不確定這兩個\t是如何變成一個\t的。 顯然我錯過了一些東西。

要評估(dist mp1 mp2) 2.0 ,讓我們從 function、 dist mp1 mp2開始:

dist mp1 mp2
= -- def dist
sqrt1 (sqr((x mp1) `sub` (x mp2)) `add` sqr ((y mp1) `sub` (y mp2)))
= -- replace the cooridanates of the two points
sqrt1 (sqr((\t -> (4.0 `add` (0.5 `mul` t))) 
           `sub`
           (\t -> (0.0 `add` (1.0 `mul` t)))) 
      `add` ...)  -- omitting the similar part
= -- the inner `add`, `mul` are the Double ones
sqrt1 (sqr((\t -> (4.0 + 0.5 * t))) 
           `sub`
           (\t -> (0.0 + 1.0 * t)))) 
      `add` ...)
= -- `sub` instead is the lifted subtraction since it's applied to `Moving Double`s
sqrt1 (sqr(\t -> (4.0 + 0.5 * t) - (0.0 + 1.0 * t))
      `add` ...)
= -- `sqr` is lifted for the same reason
sqrt1 ((\t -> sqr((4.0 + 0.5 * t) - (0.0 + 1.0 * t)))
      `add` ...)
= -- `add` is lifted, let the ... above be (\t -> ...2)
sqrt1 (\t -> sqr((4.0 + 0.5 * t) - (0.0 + 1.0 * t)) + ...2)
= -- `sqrt1` is lifted
\t -> sqrt (sqr((4.0 + 0.5 * t) - (0.0 + 1.0 * t)) + ...2)

最后,我們可以根據需要將最后一個 lambda 應用到2.0 ,得到Double結果。

請注意,要理解上述計算,重要的是要記住哪些表達式的計算結果為Double s,哪些表達式的計算結果為Moving Double s,以便我們可以根據需要進行提升。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM