繁体   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