我写了一些TemplateHaskell发出重写规则的代码,但是GHC(8.6.5)拒绝了我的规则,并出现以下错误:
Rule "mapKWith/Pure":
Illegal expression: ((mapKWith @Pure) constraintProxy)
in left-hand side: ((mapKWith @Pure) constraintProxy) func
LHS must be of form (f e1 .. en) where f is not forall'd
Run Code Online (Sandbox Code Playgroud)
如果我使用编译-ddump-splices并查看该规则,则可以看到它看起来像这样(重新格式化):
{-# RULES "mapKWith/Pure"
forall
(constraintProxy :: Proxy constraint)
(func :: forall child. constraint child => Tree m child -> Tree n child).
((mapKWith @Pure) constraintProxy) func =
\case MkPure x -> MkPure (func x)
#-}
Run Code Online (Sandbox Code Playgroud)
如果我将此规则复制到代码中并进行编辑,则只需要删除LHS的多余括号,GHC就可以接受它(这样LHS就变得mapKWith @Pure constraintProxy func没有括号了)。
有没有一种方法可以从TH发出没有多余括号的代码,以便GHC可以接受它来重写规则LHS?还有其他解决方案或解决方法吗?
对于上下文,我正在尝试生成这些规则来帮助GHC内联函数获取RankNTypes值,并且我尝试的代码可在https://github.com/lamdu/syntax-tree/blob/rewrite-rules/src中 …
为了处理文本输入,我使用设置了一个char-event回调glfwSetCharCallback,并且为了处理非文本按键(箭头键和热键),我使用设置了一个键事件回调glfwSetKeyCallback。
在这种情况下发生的情况是,对于一个字符键的按键操作,我收到两个调用,一个在键事件回调中,然后一个在char事件回调中。这可能会导致不想要的效果-例如,假设用户将键“ a”配置为进入文本编辑器的“附加模式”-进入模式后,它还将输入字符“ a”。处理这个?
到目前为止,我已经依赖于两个事件在glfwPollEvents返回之前一起到达,并且已经将它们合并。但是我得到报告说,该方案在某些Ubuntu系统上不能很好地工作。
这是我的情况:
我想调用ffmpeg的av_free_packet函数:
// avformat.h
static inline void av_free_packet(AVPacket *pkt)
{
if (pkt && pkt->destruct)
pkt->destruct(pkt);
}
Run Code Online (Sandbox Code Playgroud)
但不幸的是static inline,这个功能是,因此并没有真正出现在链接库中.
但是,这是一个非常简单的功能,我可以在Haskell中重新实现.这就是我无法弄清楚该怎么做的事情.这是部分尝试(.hsc):
av_free_packet :: Ptr AVPacket -> IO ()
av_free_packet pkt =
when (nullPtr /= pkt) $ do
destruct <- (#peek AVPacket, destruct) pkt :: IO (FunPtr (Ptr AVPacket -> IO ()))
when (nullFunPtr /= destruct) $ funPtrToFun destruct pkt
funPtrToFun :: FunPtr a -> a
funPtrToFun = ?
Run Code Online (Sandbox Code Playgroud)
现在我可以求助于在C中实现这个函数(通过调用原始函数),但在我看来,调用函数指针应该可能以某种方式..
报价'用于什么?我已经阅读了有关curried函数的内容,并阅读了两种定义add函数的方法 - curried和uncurried.咖喱版......
myadd' :: Int -> Int -> Int
myadd' x y = x + y
Run Code Online (Sandbox Code Playgroud)
......但没有引用它同样有效.那有什么意义'呢?
假设某人制作了下棋或解决数独游戏的程序.在这种程序中,有一个表示游戏状态的树结构是有意义的.
这棵树非常大,"实际上是无限的".由于Haskell支持无限数据结构,因此这本身不是问题.
一个熟悉的无限数据结构示例:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)
节点仅在首次使用时分配,因此列表占用有限的内存.如果他们不保留对其头部的引用,也可以迭代无限列表,允许垃圾收集器收集其不再需要的部分.
回到树示例 - 假设一个人在树上进行一些迭代,如果仍然需要树的根,则迭代的树节点可能不会被释放(例如,在迭代加深搜索中,树将被迭代多次因此需要保留根).
我想到的这个问题的一个可能的解决方案是使用"unmemo-monad".
我将尝试使用monadic列表来演示这个monad应该做什么:
import Control.Monad.ListT (ListT) -- cabal install List
import Data.Copointed -- cabal install pointed
import Data.List.Class
import Prelude hiding (enumFromTo)
nums :: ListT Unmemo Int -- What is Unmemo?
nums = enumFromTo 0 1000000
main = print $ div (copoint (foldlL (+) 0 nums)) (copoint (lengthL nums))
Run Code Online (Sandbox Code Playgroud)
使用时nums :: [Int],程序会在迭代nums过程中需要大量内存作为参考.lengthL numsfoldlL (+) 0 nums
目的 …
以下代码成功编译,但在使用 GHC 9.2.3 时收到警告-Wredundant-constraints:
{-# LANGUAGE UndecidableInstances, FlexibleInstances #-}\n\nclass Functor f => C f where c :: f Int\n\ninstance (Functor f, Applicative f) => C f where c = pure 42\nRun Code Online (Sandbox Code Playgroud)\n由此产生的警告:
\ntest.hs:5:10: warning: [-Wredundant-constraints]\n \xe2\x80\xa2 Redundant constraint: Functor f\n \xe2\x80\xa2 In the instance declaration for \xe2\x80\x98C f\xe2\x80\x99\n |\n5 | instance (Functor f, Applicative f) => C f where c = pure 42\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nRun Code Online (Sandbox Code Playgroud)\n但是,如果我删除此约束,代码将不再进行类型检查:
\ntest.hs:5:10: error:\n \xe2\x80\xa2 Could not deduce (Functor …Run Code Online (Sandbox Code Playgroud) 请考虑以下示例程序:
next :: Int -> Int
next i
| 0 == m2 = d2
| otherwise = 3 * i + 1
where
(d2, m2) = i `divMod` 2
loopIteration :: MaybeT (StateT Int IO) ()
loopIteration = do
i <- get
guard $ i > 1
liftIO $ print i
modify next
main :: IO ()
main = do
(`runStateT` 31) . runMaybeT . forever $ loopIteration
return ()
Run Code Online (Sandbox Code Playgroud)
它只能使用get而不是lift get因为instance MonadState s m …
认为标准Monad类有缺陷并且它应该实际扩展Functor或Pointed浮动的想法.
我不一定声称这是正确的做法,但假设有人试图这样做:
import Prelude hiding (Monad(..))
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
join = (>>= id)
(>>=) :: m a -> (a -> m b) -> m b
a >>= t = join (fmap t a)
(>>) :: m a -> m b -> m b
a >> b = a >>= const b
Run Code Online (Sandbox Code Playgroud)
到目前为止一切顺利,但在尝试使用do-notation时:
whileM :: Monad m …Run Code Online (Sandbox Code Playgroud) 干净安装"Haskell平台".(OS X Snow-Leopard&Platform 2010.1.0.1),这样做会导致简单的序列导致非常奇怪的cabal install行为:
$ cabal install time
$ cabal install random
$ ghc-pkg list random
/Library/Frameworks/GHC.framework/Versions/612/usr/lib/ghc-6.12.1/package.conf.d
random-1.0.0.2
/Users/yairc/.ghc/i386-darwin-6.12.1/package.conf.d
random-1.0.0.2
Run Code Online (Sandbox Code Playgroud)
random-1.0.0.2在我的系统中安装了两次.现在每次都要cabal install random重新安装random-1.0.0.2.
看起来random取决于time,并且cabal想要在有新版本time可用之后重新安装它?而且由于两个random-1.0.0.2阴谋混淆并总是认为它不是最新的,因为它正在看第一个?
ghc-pkg check 发现没有错误.
在Haskell中表达无限类型时:
f x = x x -- This doesn't type check
Run Code Online (Sandbox Code Playgroud)
可以使用a newtype来做到这一点:
newtype Inf = Inf { runInf :: Inf -> * }
f x = x (Inf x)
Run Code Online (Sandbox Code Playgroud)
是否存在newtype允许表达无限种类的等价物?
我已经发现我可以使用类型族来获得类似的东西:
{-# LANGUAGE TypeFamilies #-}
data Inf (x :: * -> *) = Inf
type family RunInf x :: * -> *
type instance RunInf (Inf x) = x
Run Code Online (Sandbox Code Playgroud)
但是我对这个解决方案不满意 - 不同于类型的类型,Inf不会创造一种新类型(Inf x有类型*),所以安全性较低.
这个问题有更优雅的解决方案吗?