Marlowe được nhúng trong Haskell

Trong hướng dẫn này, chúng tôi quay trở lại ví dụ ký quỹ và chỉ ra cách chúng tôi có thể sử dụng việc nhúng Marlowe vào Haskell để tạo ra các mô tả hợp đồng Marlowe dễ đọc hơn và có thể tái sử dụng.

Một hợp đồng ký quỹ đơn giản, đã được xem lại.

Nhớ lại rằng chúng tôi đã phát triển hợp đồng Marlowe này trong hướng dẫn trước đó của chúng tôi .

Trong khi chúng tôi đã trình bày nó ở đó như một hợp đồng “monolothic”, chúng tôi có thể sử dụng các định nghĩa của Haskell để làm cho nó dễ đọc hơn. Để bắt đầu, chúng ta có thể tách cam kết ban đầu khỏi phần làm việc bên trong (inner) của hợp đồng:

contract :: Contract
contract = When [Case (Deposit "alice" "alice" ada price) inner]
                1700000000
                Close

inner :: Contract
inner =
  When [ Case aliceChoice
              (When [ Case bobChoice
                          (If (aliceChosen `ValueEQ` bobChosen)
                              agreement
                              arbitrate) ]
                    1700007200
                    arbitrate)
       ]
       1700003600
       Close

Nhiều thuật ngữ ở đây được tự định nghĩa trong Haskell. Về cơ bản, chúng tôi có hai hợp đồng giải quyết những gì xảy ra khi có agreementgiữa Alice và Bob, và nếu không, Carol nên làm thế nào arbitrategiữa họ:

agreement :: Contract
agreement =
  If (aliceChosen `ValueEQ` (Constant 0))
     (Pay "alice" (Party "bob") ada price Close)
     Close

arbitrate :: Contract
arbitrate =
  When [ Case carolClose Close,
         Case carolPay (Pay "alice" (Party "bob") ada price Close) ]
       1700010800
       Close

Trong các hợp đồng này, chúng tôi cũng sử dụng các từ viết tắt đơn giản như:

price :: Value
price = Constant 450

cho biết giá của con mèo và giá trị của số tiền được ký quỹ.

Chúng tôi cũng có thể mô tả các lựa chọn được thực hiện bởi Alice và Bob, lưu ý rằng chúng tôi cũng được yêu cầu cung cấp một giá trị mặc định defValueđề phòng các lựa chọn chưa được thực hiện.

aliceChosen, bobChosen :: Value

aliceChosen = ChoiceValue (ChoiceId choiceName "alice")
bobChosen   = ChoiceValue (ChoiceId choiceName "bob")

defValue = Constant 42

choiceName :: ChoiceName
choiceName = "choice"

Khi mô tả các lựa chọn, chúng ta có thể đặt tên hợp lý cho các giá trị số:

pay,refund,both :: [Bound]

pay    = [Bound 0 0]
refund = [Bound 1 1]
both   = [Bound 0 1]

và xác định các chức năng (functions) mới (hoặc "mẫu") cho chính chúng ta. Trong trường hợp này, chúng tôi xác định

choice :: Party -> [Bound] -> Action

choice party bounds =
  Choice (ChoiceId choiceName party) bounds

như một cách làm cho việc diễn đạt các lựa chọn trở nên đơn giản hơn và dễ đọc hơn:

alicePay, aliceRefund, aliceChoice :: Action
alicePay    = choice "alice" pay
aliceRefund = choice "alice" refund
aliceChoice = choice "alice" both

Với tất cả các định nghĩa này, chúng tôi có thể viết hợp đồng ở đầu phần này theo cách làm rõ ý định của nó. Viết bằng Marlowe ``pure'', hoặc bằng cách mở rộng các định nghĩa này, chúng tôi sẽ có hợp đồng này thay thế:

When [
  (Case
     (Deposit
        "alice" "alice" ada
        (Constant 450))
     (When [
           (Case
              (Choice
                 (ChoiceId "choice" "alice") [
                 (Bound 0 1)])
              (When [
                 (Case
                    (Choice
                       (ChoiceId "choice" "bob") [
                       (Bound 0 1)])
                    (If
                       (ValueEQ
                          (ChoiceValue
                             (ChoiceId "choice" "alice"))
                          (ChoiceValue
                             (ChoiceId "choice" "bob")))
                       (If
                          (ValueEQ
                             (ChoiceValue
                                (ChoiceId "choice" "alice"))
                             (Constant 0))
                          (Pay
                             "alice"
                             (Party "bob") ada
                             (Constant 450) Close) Close)
                       (When [
                             (Case
                                (Choice
                                   (ChoiceId "choice" "carol") [
                                   (Bound 1 1)]) Close)
                             ,
                             (Case
                                (Choice
                                   (ChoiceId "choice" "carol") [
                                   (Bound 0 0)])
                                (Pay
                                   "alice"
                                   (Party "bob") ada
                                   (Constant 450) Close))] 100 Close)))] 60
                 (When [
                       (Case
                          (Choice
                             (ChoiceId "choice" "carol") [
                             (Bound 1 1)]) Close)
                       ,
                       (Case
                          (Choice
                             (ChoiceId "choice" "carol") [
                             (Bound 0 0)])
                          (Pay
                             "alice"
                             (Party "bob") ada
                             (Constant 450) Close))] 100 Close)))
      ]

Bài tập

Bạn có thể thêm những từ viết tắt nào khác vào hợp đồng ở đầu trang?

Bạn có thể phát hiện ra bất kỳ chức năng nào mà bạn có thể xác định để làm cho hợp đồng ngắn hơn, hoặc mô đun hơn không?

Ví dụ này đã cho thấy cách nhúng trong Haskell mang lại cho chúng ta một ngôn ngữ biểu đạt hơn, chỉ đơn giản bằng cách sử dụng lại một số tính năng cơ bản của Haskell, cụ thể là các định nghĩa về hằng số và hàm. Trong hướng dẫn tiếp theo, bạn sẽ tìm hiểu về cách xác định hợp đồng bằng cách sử dụng JavaScript nhúng.

Ghi chú

Bạn có thể tìm thấy một số ví dụ khác về việc sử dụng Haskell để xây dựng hợp đồng Marlowe trong Sân chơi Marlowe, nơi cũng có thể xây dựng các hợp đồng Marlowe được nhúng Haskell.

Last updated