簡體   English   中英

如何在Haskell中建立類型之間的排序

[英]How to establish an ordering between types in Haskell

我需要在* -> *類型之間建立排序,基於一種類型的每個成員可以由另一種類型表示。 這是同態。

問題是我可以定義!<=!的傳遞性!<=! 關系,但類型檢查無法搞清楚。 這也很模糊, Identity !<=! Maybe Identity !<=! Maybe可以從Identity !<=! Maybe派生出來Identity !<=! Maybe Identity !<=! Maybe還是Identity !<=! Identity !<=! Maybe Identity !<=! Identity !<=! Maybe Identity !<=! Identity !<=! Maybe ,......每個派生都有一個不同的(但等價的) repr定義。

所以我正在尋找其他方法來創造一種反思性和傳遞性的關系。

{-# LANGUAGE ScopedTypeVariables, TypeOperators, MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, AllowAmbiguousTypes, OverlappingInstances #-}

import Control.Monad.Identity
import Data.Maybe

class x !<=! y where
  repr :: x a -> y a

instance x !<=! x where
  repr = id

instance Identity !<=! Maybe where
  repr = return . runIdentity

instance Maybe !<=! [] where
  repr = maybeToList

instance (x !<=! y, y !<=! z) => x !<=! z where
  repr = r2 . r1
    where r1 :: x a -> y a
          r1 = repr
          r2 :: y a -> z a
          r2 = repr

注意:我在GHC 7.8上試過這個。 您可能必須刪除AllowAmbiguousTypes

編輯:我想做一些像repr (Identity 3 :: Identity Int) :: [Int]

問題是我們無法讓GHC對實例執行常規圖搜索。 在這種特殊情況下,如果GHC可以執行最短路徑算法,那將是更好的,因為我們的函數隨着路徑中的每個中間表示而變慢。

但是,我們可以通過將傳出邊的數量限制為1來使搜索在每個圖節點處明確,並且GHC可以處理該搜索。 這意味着每種類型最多只有一個直接表示:

{-# LANGUAGE FlexibleInstances, TypeOperators, MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances, OverlappingInstances #-}

import Control.Monad.Identity
import Data.Maybe

class DirectRepr x y | x -> y where
    directRepr :: x a -> y a

我們可以用DirectRepr構建一個圖形:

instance DirectRepr Identity Maybe where
    directRepr (Identity a) = Just a

instance DirectRepr Maybe [] where
    directRepr = maybeToList

然后使用包裝類<=遍歷它:

class x <= y where
    repr :: x a -> y a

instance x <= x where
    repr = id

instance (DirectRepr x y, y <= z) => x <= z where
    repr = repr . directRepr

main = print (repr (Identity ()) :: [()]) -- [()]

它也適用於循環圖,因為當我們達到<=的反身性情況時搜索停止了(感謝OverlappingInstances ):

data A a
data B a
data C a

instance DirectRepr A B where directRepr = undefined 
instance DirectRepr B C where directRepr = undefined
instance DirectRepr C A where directRepr = undefined

foo :: A Int
foo = repr (undefined :: B Int)

如果起始類型導致循環,並且我們在循環中沒有端點類型,則搜索卡住並且我們得到上下文溢出。 這不應該打擾我們,因為這會使上下文溢出錯誤等同於簡單的“無實例”錯誤。

bar :: Maybe Int -- context overflow
bar = repr (undefined :: A Int)

僅通過推理可能無法做到這一點。 我使用Template Haskell創建了另一個解決方案,生成可以從更簡單的實例派生的所有實例。 庫的用法如下所示:

$(makeMonadRepr ''Identity          ''Maybe                     [e| return . runIdentity |])
$(makeMonadRepr ''Identity          ''IO                        [e| return . runIdentity |])
$(makeMonadRepr ''Maybe             [t| MaybeT IO |]            [e| MaybeT . return |])
$(makeMonadRepr ''IO                [t| MaybeT IO |]            [e| MaybeT . liftM Just |])
$(makeMonadRepr ''Maybe             TH.ListT                    [e| maybeToList |])
$(makeMonadRepr TH.ListT            [t| Trans.ListT IO |]       [e| Trans.ListT . return |])
$(makeMonadRepr ''IO                [t| Trans.ListT IO |]       [e| Trans.ListT . liftM (:[]) |])
$(makeMonadRepr [t| MaybeT IO |]    [t| Trans.ListT IO |]       [e| Trans.ListT . liftM maybeToList . runMaybeT |])

這將生成可以從反身性或傳遞性中導出的所有實例。 插入一個調用makeMonadRepr的新節點后,將創建所有可makeMonadRepr邊,因此用戶可以擴展這樣的結構。

這可能不是最優雅的解決方案,所以我對其他想法持開放態度。

暫無
暫無

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

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