ใน F # การใช้ตัวดำเนินการเดินหน้าท่อ|>
เป็นเรื่องปกติ อย่างไรก็ตามใน Haskell ฉันเคยเห็นแค่การใช้องค์ประกอบของฟังก์ชัน(.)
เท่านั้น ฉันเข้าใจว่ามันเกี่ยวข้องกันแต่มีเหตุผลด้านภาษาหรือไม่ที่ไม่ได้ใช้ไพพ์ฟอร์เวิร์ดใน Haskell หรือเป็นอย่างอื่น
ใน F # การใช้ตัวดำเนินการเดินหน้าท่อ|>
เป็นเรื่องปกติ อย่างไรก็ตามใน Haskell ฉันเคยเห็นแค่การใช้องค์ประกอบของฟังก์ชัน(.)
เท่านั้น ฉันเข้าใจว่ามันเกี่ยวข้องกันแต่มีเหตุผลด้านภาษาหรือไม่ที่ไม่ได้ใช้ไพพ์ฟอร์เวิร์ดใน Haskell หรือเป็นอย่างอื่น
คำตอบ:
ฉันกำลังเก็งกำไรเล็กน้อย ...
วัฒนธรรม : ฉันคิดว่า|>
เป็นตัวดำเนินการที่สำคัญใน F # "วัฒนธรรม" และอาจจะคล้ายกันกับ.
Haskell F # มีตัวดำเนินการจัดองค์ประกอบฟังก์ชัน<<
แต่ฉันคิดว่าชุมชน F # มีแนวโน้มที่จะใช้รูปแบบที่ไม่มีจุดน้อยกว่าชุมชน Haskell
ความแตกต่างของภาษา : ฉันไม่รู้เกี่ยวกับภาษาทั้งสองมากพอที่จะเปรียบเทียบได้ แต่บางทีกฎสำหรับการสรุปการเชื่อมโยงแบบทั่วไปอาจแตกต่างกันพอสมควรที่จะส่งผลต่อสิ่งนี้ ตัวอย่างเช่นฉันรู้ว่าใน F # บางครั้งก็เขียน
let f = exp
จะไม่คอมไพล์และคุณต้องการ eta-conversion อย่างชัดเจน:
let f x = (exp) x // or x |> exp
เพื่อให้คอมไพล์ นอกจากนี้ยังนำผู้คนออกจากรูปแบบที่ไม่มีจุด / องค์ประกอบและไปสู่รูปแบบท่อ นอกจากนี้การอนุมานประเภท F # บางครั้งต้องการการวางท่อเพื่อให้ประเภทที่รู้จักปรากฏทางด้านซ้าย (ดูที่นี่ )
(โดยส่วนตัวแล้วฉันพบว่ารูปแบบที่ไม่มีจุดอ่านไม่ได้ แต่ฉันคิดว่าทุกสิ่งใหม่ / แตกต่างดูเหมือนจะไม่สามารถอ่านได้จนกว่าคุณจะคุ้นเคยกับมัน)
ฉันคิดว่าทั้งสองอย่างสามารถทำงานได้ในภาษาใดภาษาหนึ่งและประวัติศาสตร์ / วัฒนธรรม / อุบัติเหตุอาจเป็นตัวกำหนดว่าทำไมแต่ละชุมชนจึงตั้งถิ่นฐานด้วย "ตัวดึงดูด" ที่แตกต่างกัน
.
และ$
ผู้คนยังคงใช้มันต่อไป
ใน F # (|>)
มีความสำคัญเนื่องจากการตรวจสอบการพิมพ์จากซ้ายไปขวา ตัวอย่างเช่น:
List.map (fun x -> x.Value) xs
โดยทั่วไปจะไม่พิมพ์ดีดเพราะแม้ว่าxs
จะทราบประเภทของอาร์กิวเมนต์x
แต่ก็ไม่ทราบประเภทของอาร์กิวเมนต์ของแลมบ์ดาในขณะที่ตัวตรวจสอบตัวพิมพ์เห็นดังนั้นจึงไม่ทราบวิธีแก้ไขx.Value
เห็นมันจึงไม่ทราบวิธีการแก้ปัญหา
ในทางตรงกันข้าม
xs |> List.map (fun x -> x.Value)
จะทำงานได้ดีเนื่องจากประเภทของxs
จะนำไปสู่ประเภทของx
การเป็นที่รู้จัก
typechecking x.Value
ซ้ายไปขวาถูกต้องเนื่องจากความละเอียดชื่อที่เกี่ยวข้องในการสร้างเช่น Simon Peyton Jones ได้เขียนข้อเสนอสำหรับการเพิ่มการแก้ไขชื่อที่คล้ายกันให้กับ Haskell แต่เขาแนะนำให้ใช้ข้อ จำกัด ในท้องถิ่นเพื่อติดตามว่าประเภทรองรับการดำเนินการเฉพาะหรือไม่แทน ดังนั้นในตัวอย่างแรกข้อกำหนดที่x
ต้องการValue
คุณสมบัติจะถูกยกยอดไปจนกว่าจะxs
เห็นและข้อกำหนดนี้สามารถแก้ไขได้ สิ่งนี้จะทำให้ระบบประเภทซับซ้อนขึ้น
การเก็งกำไรเพิ่มเติมคราวนี้จากด้าน Haskell ที่โดดเด่น ...
($)
เป็นการพลิกกลับ(|>)
และการใช้งานค่อนข้างบ่อยเมื่อคุณไม่สามารถเขียนโค้ดแบบไม่มีจุดได้ ดังนั้นเหตุผลหลักที่(|>)
ไม่ได้ใช้ใน Haskell คือสถานที่นั้นถูกยึดครองไปแล้ว($)
คือว่าสถานที่ที่ถูกใช้ไปแล้วโดย
นอกจากนี้จากประสบการณ์ F # เล็กน้อยฉันคิดว่า(|>)
มันเป็นที่นิยมมากในรหัส F # เพราะคล้ายกับSubject.Verb(Object)
โครงสร้างของ OO เนื่องจาก F # มีเป้าหมายเพื่อการรวมฟังก์ชัน / OO ที่Subject |> Verb Object
ราบรื่นจึงเป็นการเปลี่ยนแปลงที่ราบรื่นสำหรับโปรแกรมเมอร์ที่ใช้งานได้ใหม่
โดยส่วนตัวแล้วฉันชอบคิดแบบซ้ายไปขวาด้วยดังนั้นฉันจึงใช้(|>)
ใน Haskell แต่ฉันไม่คิดว่าคนอื่นจะทำ
Data.Sequence.|>
แต่$>
ดูมีเหตุผลเพื่อหลีกเลี่ยงความขัดแย้งที่นั่น จริงๆแล้วมีเพียงโอเปอเรเตอร์หน้าตาดีจำนวนมากดังนั้นฉันจะใช้|>
สำหรับทั้งสองอย่างและจัดการความขัดแย้งเป็นกรณี ๆ ไป (นอกจากนี้ฉันจะถูกล่อลวงให้ใช้นามแฝงData.Sequence.|>
ว่าsnoc
)
($)
และ(|>)
เป็นแอปพลิเคชันที่ไม่มีองค์ประกอบ ทั้งสองมีความสัมพันธ์กัน (ตามที่บันทึกคำถาม) แต่ไม่เหมือนกัน (ของคุณfc
มี(Control.Arrow.>>>)
ไว้สำหรับฟังก์ชัน)
|>
ทำให้ฉันนึกถึง UNIX |
มากกว่าสิ่งอื่นใด
|>
F # คือมีคุณสมบัติที่ดีสำหรับ IntelliSense ใน Visual Studio พิมพ์|>
และคุณจะได้รับรายการฟังก์ชันที่สามารถนำไปใช้กับค่าทางด้านซ้ายคล้ายกับสิ่งที่เกิดขึ้นเมื่อพิมพ์.
หลังวัตถุ
ฉันคิดว่าเรากำลังสับสน Haskell's ( .
) เทียบเท่ากับ F # ( >>
) อย่าสับสนกับ F # 's ( |>
) ซึ่งเป็นเพียงแอปพลิเคชันฟังก์ชันกลับด้านและเหมือนกับ Haskell's ( $
) - ย้อนกลับ:
let (>>) f g x = g (f x)
let (|>) x f = f x
ฉันเชื่อว่าโปรแกรมเมอร์ของ Haskell $
มักจะใช้ อาจจะไม่บ่อยเท่าที่ F # |>
โปรแกรมเมอร์มีแนวโน้มที่จะใช้งาน ในทางกลับกัน F # บางคนใช้>>
ในระดับที่ไร้สาระ: http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx
$
ผู้ประกอบการ - กลับคุณยังสามารถกำหนดได้อย่างง่ายดายเช่นa |> b = flip ($)
ซึ่งจะกลายเป็นเทียบเท่ากับ F # 's ท่อเช่นนั้นคุณสามารถทำได้[1..10] |> map f
.
) เหมือนกับ ( <<
) ในขณะที่ ( >>
) คือองค์ประกอบย้อนกลับ นั่นคือ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
vs( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
.
จะเทียบเท่ากับ>>
. ฉันไม่รู้ว่ามี F # หรือเปล่า<<
แต่มันจะเทียบเท่า (เหมือนใน Elm)
หากคุณต้องการใช้ F # |>
ใน Haskell ดังนั้นในData Functionคือตัว&
ดำเนินการ (ตั้งแต่base 4.8.0.0
)
&
มากกว่านี้|>
? ฉันรู้สึกว่า|>
ใช้งานง่ายกว่ามากและยังทำให้ฉันนึกถึงตัวดำเนินการท่อ Unix ด้วย
&
ใช้งานง่ายมาก โค้ดเกือบจะอ่านได้อย่างถูกต้องในภาษาอังกฤษเพียงแค่ออกเสียง&
เป็น "และ" ตัวอย่างเช่น: 5 & factorial & show
อ่านออกเสียงว่า "take 5 แล้วหาแฟกทอเรียลจากนั้นจึงใช้ show to it"
บางคนใช้รูปแบบซ้ายไปขวา (ส่งข้อความ) ใน Haskell ด้วย ดูตัวอย่างเช่นไลบรารีmpsใน Hackage ตัวอย่าง:
euler_1 = ( [3,6..999] ++ [5,10..999] ).unique.sum
ฉันคิดว่าสไตล์นี้ดูดีในบางสถานการณ์ แต่อ่านยากกว่า (ต้องรู้จักไลบรารีและตัวดำเนินการทั้งหมดคำจำกัดความใหม่(.)
ก็รบกวนเช่นกัน)
นอกจากนี้ยังมีตัวดำเนินการจัดองค์ประกอบแบบซ้ายไปขวาและขวาไปซ้ายในControl.Categoryซึ่งเป็นส่วนหนึ่งของแพ็กเกจพื้นฐาน เปรียบเทียบ>>>
และ<<<
ตามลำดับ:
ghci> :m + Control.Category
ghci> let f = (+2) ; g = (*3) in map ($1) [f >>> g, f <<< g]
[9,5]
มีเหตุผลที่ดีที่จะชอบการจัดองค์ประกอบแบบซ้ายไปขวาในบางครั้ง: ลำดับการประเมินตามลำดับการอ่าน
ฉันเคยเห็นว่ามัน>>>
ถูกใช้flip (.)
และฉันมักจะใช้มันเองโดยเฉพาะอย่างยิ่งสำหรับโซ่ยาวที่เข้าใจได้ดีที่สุดจากซ้ายไปขวา
>>>
จริงๆแล้วมาจาก Control.Arrow และทำงานได้มากกว่าฟังก์ชัน
>>>
ถูกกำหนดไว้ในControl.Category
.
นอกเหนือจากรูปแบบและวัฒนธรรมแล้วสิ่งนี้ยังช่วยเพิ่มประสิทธิภาพการออกแบบภาษาสำหรับรหัสบริสุทธิ์หรือไม่บริสุทธิ์
ตัว|>
ดำเนินการเป็นเรื่องปกติใน F # ส่วนใหญ่เนื่องจากช่วยซ่อนข้อ จำกัด สองประการที่ปรากฏพร้อมกับรหัสที่ไม่บริสุทธิ์เป็นส่วนใหญ่:
โปรดทราบว่าข้อ จำกัด เดิมไม่มีอยู่ใน OCaml เนื่องจากการพิมพ์ย่อยเป็นโครงสร้างแทนที่จะเป็นเพียงเล็กน้อยดังนั้นประเภทโครงสร้างจึงสามารถปรับแต่งได้อย่างง่ายดายผ่านการรวมกันเมื่อการอนุมานประเภทดำเนินไป
Haskell ทำการแลกเปลี่ยนที่แตกต่างกันโดยเลือกที่จะมุ่งเน้นไปที่โค้ดส่วนใหญ่ที่บริสุทธิ์ซึ่งสามารถยกเลิกข้อ จำกัด เหล่านี้ได้
ฉันคิดว่าตัวดำเนินการไปป์ฟอร์เวิร์ดของ F # |>
ควรเทียบกับ( & )ใน haskell
// pipe operator example in haskell
factorial :: (Eq a, Num a) => a -> a
factorial x =
case x of
1 -> 1
_ -> x * factorial (x-1)
// terminal
ghic >> 5 & factorial & show
หากคุณไม่ชอบ&
ตัวดำเนินการ( ) คุณสามารถกำหนดเองได้เช่น F # หรือ Elixir:
(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 1 |>
ghci>> 5 |> factorial |> show
ทำไมinfixl 1 |>
? ดูเอกสารในฟังก์ชันข้อมูล (&)
infixl = infix + การเชื่อมโยงด้านซ้าย
infixr = infix + right Associativity
( .
) หมายถึงองค์ประกอบของฟังก์ชัน หมายถึง(fg) (x) = f (g (x))ในคณิตศาสตร์
foo = negate . (*3)
// ouput -3
ghci>> foo 1
// ouput -15
ghci>> foo 5
มันเท่ากับ
// (1)
foo x = negate (x * 3)
หรือ
// (2)
foo x = negate $ x * 3
( $
) ผู้ประกอบการยังเป็นให้คำจำกัดความในข้อมูลฟังก์ชั่น ($)
( .
) ใช้สำหรับสร้างหรือHight Order Function
closure in js
ดูตัวอย่าง:
// (1) use lamda expression to create a Hight Order Function
ghci> map (\x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]
[-5,-3,-6,-7,-3,-2,-19,-24]
// (2) use . operator to create a Hight Order Function
ghci> map (negate . abs) [5,-3,-6,7,-3,2,-19,24]
[-5,-3,-6,-7,-3,-2,-19,-24]
ว้าวน้อยกว่า (รหัส) ดีกว่า
|>
และ.
ghci> 5 |> factorial |> show
// equals
ghci> (show . factorial) 5
// equals
ghci> show . factorial $ 5
มันแตกต่างกันระหว่างและleft —> right
right —> left
⊙﹏⊙ |||
|>
และ &
ดีกว่า.
เพราะ
ghci> sum (replicate 5 (max 6.7 8.9))
// equals
ghci> 8.9 & max 6.7 & replicate 5 & sum
// equals
ghci> 8.9 |> max 6.7 |> replicate 5 |> sum
// equals
ghci> (sum . replicate 5 . max 6.7) 8.9
// equals
ghci> sum . replicate 5 . max 6.7 $ 8.9
โปรดไปที่http://reactivex.io/
รองรับ:
นี่เป็นวันแรกของฉันในการลองใช้ Haskell (หลังจาก Rust และ F #) และฉันสามารถกำหนดตัวดำเนินการ F # s |>:
(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 0 |>
และดูเหมือนว่าจะใช้งานได้:
factorial x =
case x of
1 -> 1
_ -> x * factorial (x-1)
main =
5 |> factorial |> print
ฉันพนันได้เลยว่าผู้เชี่ยวชาญของ Haskell สามารถให้ทางออกที่ดียิ่งขึ้นแก่คุณได้
x |> f = f x
&
เป็นของ|>
Haskell ฝังลึกลงไปในเธรดนี้และใช้เวลาสองสามวันในการค้นพบ ฉันใช้มันบ่อยมากเพราะคุณมักจะอ่านจากซ้ายไปขวาเพื่อติดตามรหัสของคุณ