使用`runST`和类型键入函数的签名

时间:2016-12-22 05:41:04

标签: haskell

我想知道g的适当类型签名是什么。我目前得到的那个不编译。我认为某处需要forall.,但我不确定在哪里。

{-# LANGUAGE TypeFamilies #-}

import Control.Monad.ST (ST, runST)

data D

class C t where
  type M t :: * -> *
  f :: t -> M t D

g :: (C t, M t ~ ST s) => t -> D
g x = runST (f x)

main = return ()

(在回应@cirdec的评论时添加了示例)

{-# LANGUAGE TypeFamilies #-}

import Control.Monad.ST (ST, runST)

data D = D

class C t where
  type M t :: * -> *
  f :: t -> M t D

data T (m :: (* -> *)) = T

instance (Monad m) => C (T m) where
  type M (T m) = m
  f _ = return D

main = const (return ()) (runST (f T))

然后我用以下内容替换main

g x = runST (f x)
main = const (return ()) (g T)

根据它的外观,这应按照g T == runST (f T)的定义编译为g。但事实并非如此。我认为g需要签名,但我不确定它是什么。

(添加了@cirdec评论的背景)

基本上在我的代码中C是一类数据类型,可以被视为monadic disjoint Int sets(我知道hackage上已有包但我的方法还有一些功能)。 C具有unionfind等函数。这些函数的实际实现取决于用户是否在创建时知道其大小或是否需要动态增长,因此类型类。但是,一旦创建了这些数据类型,就可以粗略地对待它们。所有这些都发生在monad代码中,通常是STIO,但技术上MonadRef中的任何内容都足够了。然后C具有结果类型freeze的函数M t D,其中D是某种结果数据类型。例如,对于IO,冻结的类型为(C t) => t -> IO D,但ST freeze的内容更像(C t) => t -> ST s D。在后一种情况下,应该能够在runST的结果上运行freeze来获取原始结果数据。

1 个答案:

答案 0 :(得分:2)

以下文件为我编译:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}

import Control.Monad.ST (ST, runST)

data D = D

class C t where
  type M t :: * -> *
  f :: t -> M t D

data T (m :: (* -> *)) = T

instance (Monad m) => C (T m) where
  type M (T m) = m
  f _ = return D

data Equal a b where Refl :: Equal a a

convert :: Equal f g -> f a -> g a
convert Refl v = v

data Box s where
    Box :: C t => Equal (M t) (ST s) -> t -> Box s

g :: (forall s. Box s) -> D
g box = runST (case box of Box eq x -> convert eq (f x))

main = const (return ()) (g (Box Refl T))