简体   繁体   English

重新讨论具有约束种类的多态STUArrays

[英]Revisiting Polymorphic STUArrays with Constraint Kinds

I want to implement a dynamic programming algorithm polymorphic in the score type; 我想在得分类型中实现动态编程算法多态; here's a simplified 1D version with no boundary conditions: 这是一个没有边界条件的简化1D版本:

{-# LANGUAGE ConstraintKinds, FlexibleContexts, RankNTypes, ScopedTypeVariables #-}

import Control.Monad
import Control.Monad.ST.Strict
import Data.Array.ST
import Data.Array.Unboxed

dynamicProgrammingSTU
  :: forall e i . (
    IArray UArray e,
    forall s. MArray (STUArray s) e (ST s),
    Ix i
  )
  => (forall m . Monad m => (i -> m e) -> (i -> m e))
  -> (i, i)
  -> (i -> e)
dynamicProgrammingSTU prog bnds = (arr !) where
  arr :: UArray i e
  arr = runSTUArray resultArrayST

  resultArrayST :: forall s . ST s (STUArray s i e)
  resultArrayST = do
    marr <- newArray_ bnds
    forM_ (range bnds) $ \i -> do
      result <- prog (readArray marr) i
      writeArray marr i result
    return marr

The constraint doesn't work; 约束不起作用;

    Could not deduce (MArray (STUArray s) e (ST s))
      arising from a use of `newArray_'
    from the context (IArray UArray e,
                      forall s. MArray (STUArray s) e (ST s),
                      Ix i)
      bound by the type signature for
                 dynamicProgrammingSTU :: (IArray UArray e,
                                           forall s. MArray (STUArray s) e (ST s
), Ix i) =>
                                          (forall (m :: * -> *). Monad m => (i -
> m e) -> i -> m e)
                                          -> (i, i) -> i -> e
      at example2.hs:(17,1)-(27,15)
    Possible fix:
      add (MArray (STUArray s) e (ST s)) to the context of
        the type signature for resultArrayST :: ST s (STUArray s i e)
        or the type signature for
             dynamicProgrammingSTU :: (IArray UArray e,
                                       forall s. MArray (STUArray s) e (ST s), I
x i) =>
                                      (forall (m :: * -> *). Monad m => (i -> m
e) -> i -> m e)
                                      -> (i, i) -> i -> e
      or add an instance declaration for (MArray (STUArray s) e (ST s))
    In a stmt of a 'do' block: marr <- newArray_ bnds
    In the expression:
      do { marr <- newArray_ bnds;
           forM_ (range bnds) $ \ i -> do { ... };
           return marr }
    In an equation for `resultArrayST':
        resultArrayST
          = do { marr <- newArray_ bnds;
                 forM_ (range bnds) $ \ i -> ...;
                 return marr }
Failed, modules loaded: none.

To summarize, Could not deduce (MArray (STUArray s) e (ST s)) from the context forall s. MArray (STUArray s) e (ST si) 总而言之, Could not deduce (MArray (STUArray s) e (ST s)) from the context forall s. MArray (STUArray s) e (ST si) Could not deduce (MArray (STUArray s) e (ST s)) from the context forall s. MArray (STUArray s) e (ST si) . Could not deduce (MArray (STUArray s) e (ST s)) from the context forall s. MArray (STUArray s) e (ST si) Note that adding the constraint to resultArrayST just pushes the problem to runSTUArray . 请注意,将约束添加到resultArrayST只是将问题推送到runSTUArray

I currently know of four flawed solutions: 我目前知道四个有缺陷的解决方案:

  1. Avoiding the problem with boxed STArray s or simply non-monadic Array s, perhaps using seq and bang patterns to ease the resulting memory problems. 避免使用盒装的STArray或简单的非STArray Array ,可能使用seq和bang模式来缓解由此产生的内存问题。
  2. Breaking the type system with unsafeFreeze and unsafePerformIO , for which the damning constraint MArray IOUArray e IO works fine. 使用unsafeFreezeunsafePerformIO打破类型系统, unsafeFreeze诅咒约束MArray IOUArray e IO工作正常。
  3. This solution to a similar problem using a typeclass and writing instances for every 'unboxable' type. 解决了类似问题,使用类型类并为每个'unboxable'类型编写实例。
  4. This one using GHC rewrite rules to pick a different function for each type (and a generic STArray version). 这个使用GHC重写规则为每种类型选择不同的函数(以及通用的STArray版本)。

However, I'm asking this question in the hopes that modern language extensions like ConstraintKinds can allow me to express my original code's intent of forall s. MArray (STUArray s) e (ST s) 但是,我问这个问题是希望像ConstraintKinds这样的现代语言扩展可以让我表达我原来代码的意图forall s. MArray (STUArray s) e (ST s) forall s. MArray (STUArray s) e (ST s) . forall s. MArray (STUArray s) e (ST s)

Given the legendary helpfulness of the Haskell community, the lack of an answer at this point is a strong indication that there's no good solution in the current type system. 鉴于Haskell社区的传奇帮助,此时缺乏答案强烈表明当前类型系统没有好的解决方案。

I've already outlined the flawed solutions in the question, so I'll just post a complete version of my example. 我已经在问题中概述了有缺陷的解决方案,所以我将发布我的示例的完整版本。 This is basically what I used to solve most alignment problems on Rosalind: 这基本上就是我用来解决Rosalind上大多数对齐问题的原因:

{-# LANGUAGE FlexibleContexts, RankNTypes, ScopedTypeVariables #-}

import Control.Applicative
import Control.Monad
import Control.Monad.ST
import Data.Maybe

import Data.Array.ST
import Data.Array.Unboxed

class IArray UArray e => Unboxable e where
  newSTUArray_ :: forall s i. Ix i => (i, i) -> ST s (STUArray s i e)
  readSTUArray :: forall s i. Ix i => STUArray s i e -> i -> ST s e
  writeSTUArray :: forall s i. Ix i => STUArray s i e -> i -> e -> ST s ()


instance Unboxable Bool where 
  newSTUArray_ = newArray_
  readSTUArray = readArray
  writeSTUArray = writeArray

instance Unboxable Double where 
  newSTUArray_ = newArray_
  readSTUArray = readArray
  writeSTUArray = writeArray
{-
Same for Char, Float, (Int|Word)(|8|16|32|64)...
-}

{-# INLINE dynamicProgramming2DSTU #-}
dynamicProgramming2DSTU
  :: forall e i j . (
    Unboxable e,
    Ix i,
    Ix j,
    Enum i,
    Enum j
  )
  => (forall m . (Monad m, Applicative m) => (i -> j -> m e) -> (i -> j -> m e))
  -> (i -> j -> Maybe e)
  -> (i, i)
  -> (j, j)
  -> (i -> j -> e)
dynamicProgramming2DSTU program boundaryConditions (xl, xh) (yl, yh) = arrayLookup where
  arrayLookup :: i -> j -> e
  arrayLookup xi yj = fromMaybe (resultArray ! (xi, yj)) $ boundaryConditions xi yj

  arrB :: ((i, j), (i, j))
  arrB = ((xl, yl), (xh, yh))

  resultArray :: UArray (i, j) e
  resultArray = runSTUArray resultArrayST

  resultArrayST :: forall s. ST s (STUArray s (i, j) e)
  resultArrayST = do
    arr <- newSTUArray_ arrB
    let acc xi yj = maybe (readSTUArray arr (xi, yj)) return $ boundaryConditions xi yj

    forM_ [xl..xh] $ \xi -> do
      forM_ [yl..yh] $ \yj -> do
        result <- program acc xi yj
        writeSTUArray arr (xi, yj) result

    return arr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM