当前位置: 首页 > 知识库问答 >
问题:

用线性类型降低高阶函数

戚宏浚
2023-03-14

我最近一直在试验线性类型,一直在想下面的转换是否可能。如果没有线性类型,它肯定是无效的。

目的是降低高阶函数参数。这应该是可以的,因为线性类型确保HOF只被调用一次,所以正好存在一个a值。问题是如何避开lambda并观察a

   lower :: ((a %1-> b) %1-> r) %1-> b %1-> (r,a)

共有1个答案

袁晟
2023-03-14

编辑:您无法安全地执行降低。正如dfeuer和danidiaz在评论中所说:如果lower的第一个参数是身份函数呢?通过我在下面的旧答案中展示的实现,你可以写:

main :: IO ()
main = putStrLn (snd (lower (\x -> x) False))

这将在运行时产生错误:

Lin: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:74:14 in base:GHC.Err
  undefined, called at Lin.hs:25:19 in main:Main

所以线性类型没有给出足够的保证来安全地实现这个函数。

Edit2:您可以通过将签名稍微更改为:下级:: ((%1-

import Control.Exception (evaluate)

-- from Data.Unrestricted.Linear from linear-base
data Ur a where
  Ur :: a -> Ur a

lower :: ((a %1 -> b) %1 -> Ur r) %1 -> b %1 -> (Ur r, a)
lower = toLinear2 lower'

lower' :: ((a %1 -> b) %1 -> Ur r) -> b -> (Ur r, a)
lower' f b = unsafePerformIO $ do
  ref <- newIORef undefined
  r <- evaluate $ f (toLinear (\a -> unsafePerformIO $ b <$ writeIORef ref a))
  a <- readIORef ref
  pure (r, a)

这可能不是你要找的答案,但是如果你确定它是安全的,那么你可以稍微改变一下规则:

{-# LANGUAGE LinearTypes, GADTs #-}
import System.IO.Unsafe
import Data.IORef
import Unsafe.Coerce
import Control.Exception (evaluate)

-- 'coerce', 'toLinear' and 'toLinear2' are also found in Unsafe.Linear from linear-base

coerce :: forall a b. a %1-> b
coerce a =
  case unsafeEqualityProof @a @b of
    UnsafeRefl -> a
{-# INLINE coerce #-}

toLinear :: (a %p-> b) %1-> (a %1-> b)
toLinear = coerce

toLinear2 :: (a %p-> b %q-> c) %1-> (a %1-> b %1-> c)
toLinear2 = coerce

lower :: ((a %1 -> b) %1 -> r) %1 -> b %1 -> (r, a)
lower = toLinear2 lower'

lower' :: ((a %1 -> b) %1 -> r) -> b -> (r, a)
lower' f b = unsafePerformIO $ do
  ref <- newIORef undefined
  r <- evaluate $ f (toLinear (\a -> unsafePerformIO $ b <$ writeIORef ref a))
  a <- readIORef ref
  pure (r, a)

我认为线性类型的主要目的只是获取额外的类型级别信息,所以我认为没有任何安全的原语可以让您更清晰地完成这项工作(尽管我不知道所有细节)。线性类型确实允许您实现一个安全的接口,其中包含不安全的操作。例如,请参见此文件中使用线性基的次数toLinear

也许上面不安全的部分可以外包给较低级别的库。也许有点像promise,但也有线性类型。

 类似资料:
  • 我对打字稿非常兴奋。如何设置函数参数的类型? 我怎样才能更好地输入?我想指定它必须是一个接受数字并返回数字的函数。 然后我能为这种类型做一个“接口”或一些简写,这样我就能让我的高阶函数签名更具可读性吗?

  • 我现在在学习哈斯克尔。但我正在为“类型”而挣扎。 例如,函数的类型是

  • 常用高阶函数 1.map 对于原始集合里的每一个元素, 以一个变换后的元素替换之形成一个新的集合 1.1 flatmap 对于元素是集合的集合, 可以得到单级的集合 let results = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] let allResults = results.flatMap{ $0.map{ $0 * 10 } } let passMarks =

  • Haskell 中的函数可以接受函数作为参数也可以返回函数作为结果,这样的函数就被称作高阶函数。高阶函数可不只是某简单特性而已,它贯穿于 Haskell 的方方面面。要拒绝循环与状态的改变而通过定义问题"是什么"来解决问题,高阶函数必不可少。它们是编码的得力工具。 Curried functions 本质上,Haskell 的所有函数都只有一个参数,那么我们先前编那么多含有多个参数的函数又是怎么回

  • 简介 高阶函数(Higher Order Function)是一种以函数为参数的函数。它们都被用于映射(mapping)、过滤(filtering)、归档(folding)和排序(sorting)表。高阶函数提高了程序的模块性。编写对各种情况都适用的高阶函数与为单一情况编写递归函数相比,可以使程序更具可读性。比如说,使用一个高阶函数来实现排序可以使得我们使用不同的条件来排序,这就将排序条件和排序过

  • 高阶函数英文叫Higher-order function。那么什么是高阶函数? JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。 一个最简单的高阶函数: function add(x, y, f) { return f(x) + f(y); } 当我们调用add(-5, 6, M