(Vi) Kleisli composition và ứng dụng thực tế

Posted on December 8, 2022 by lk
Tags: haskell, kleisli

(Vi) Kleisli composition và ứng dụng thực tế

Giả sử chúng ta có 2 hàm số monadic (monadic function) f và g như sau

note: monadic function là hàm số nhận vào một tham số a bất kỳ và trả vệ một giá trị b nằm trong 1 context/action hay một computation nào đó

f     :: A -> T (B)
g     :: B -> T (C) 

Liệu có cách nào để combine 2 hàm số f và g có kết quả trả về như sau

?? g f ::                  A ->              T (C)
??     :: (B -> T (C)) -> (A -> T (B))-> (A->T(C)) -- thay g f vào vế trái 

chúng ta cần

g' :: T (B) -> T (C)

để có

g' . f :: (TB ->TC)-> (A->TB) -> (A ->TC)

(=<<) :: B -> T(C) -> T(B) -> T(C) cho nên

g' = (=<<) g

do đó

f      :: A -> T (B)
g      :: B -> T (C)
g'     :: T B -> T C where g' = (=<<) g)

g' . f :: A -> T C

??  g f = g' .f = ((=<<) g) . f
>=> g f = g' .f = ((=<<) g) . f

?? -> >=> còn gọi là fishy operator

g >=> f :: (B -> T (C)) -> (A -> T (B))-> (A->T(C)) -- Kleisli composition

Ứng dụng của Kleisli composition

Như chúng ta có thể thấy ở trên, bản chất của Kleisli composition vẫn dựa trên monadic function và hàm bind >>= của Monad. Chúng ta ít thấy Kleisli được sử dụng trong thực tế, tuy nhiên với thư viện xml-conduit khi làm việc với xml chúng ta thấy được sự tiện lợi khi dùng Kleisli (>=>)

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Prelude hiding (readFile)
import Text.XML
import Text.XML.Cursor
import qualified Data.Text as T
import System.Directory(getCurrentDirectory)

main :: IO ()
main = do
    currDir <- getCurrentDirectory
    putStrLn $ "currDir " <> currDir
    doc <- readFile def $ currDir <> "/test2.xml"
    let cursor = fromDocument doc
    print $ T.concat $
        cursor $// element "h2"
               >=> attributeIs "class" "bar"
               >=> precedingSibling
               >=> element "h1"
               &// content

với file test2.xml có nội dung như sau

<html>
    <head>
        <title>Headings</title>
    </head>
    <body>
        <hgroup>
            <h1>Heading 1 foo</h1>
            <h2 class="foo">Heading 2 foo</h2>
        </hgroup>
        <hgroup>
            <h1>Heading 1 bar</h1>
            <h2 class="bar">Heading 2 bar</h2>
        </hgroup>
    </body>
</html>

Đoạn code trên sẽ in ra kết quả gì, bạn hãy thử xem nhé!

hint: cần tìm các element tag là h2 và thoả class name là bar, sau đó tìm element kế trước nó và in ra content

Bạn có thể tham khảo repo này nhé https://github.com/ahaxu/test-xml/

Tham khảo