为什么 GHC 不认为函数是线性的?
Why doesn't GHC recognize the function as linear?
我有一个非常简单的片段:
{-# LANGUAGE LinearTypes #-}
module Lib where
data Peer st = Peer { data :: String } deriving Show
data Idle
data Busy
sendToPeer :: Peer Idle %1-> Int -> IO (Peer Busy)
sendToPeer c n = case c of Peer d -> pure $ Peer d
我在 resolver: ghc-9.0.1
.
A function f is linear if: when its result is consumed exactly once,
then its argument is consumed exactly once. Intuitively, it means that
in every branch of the definition of f, its argument x must be used
exactly once. Which can be done by
- Returning x unmodified
- Passing x to a linear function
- Pattern-matching on x and using each argument exactly once in the same fashion.
- Calling it as a function and using the result exactly once in the same fashion.
而我的函数 sendToPeer
正是这样做的 - 在 c
上进行模式匹配并且它的参数 d
使用一次 - 在 Peer d
中是线性的:
By default, all fields in algebraic data types are linear (even if
-XLinearTypes is not turned on).
但是我得到一个错误:
• Couldn't match type ‘'Many’ with ‘'One’
arising from multiplicity of ‘c’
• In an equation for ‘sendToPeer’:
sendToPeer c n = case c of { Peer d -> pure $ Peer d }
|
11 | sendToPeer c n =
| ^
没有pure
:
sendToPeer :: Peer Idle %1-> Int -> Peer Busy
sendToPeer c n = case c of Peer d -> Peer d
但错误是一样的
使用 Control.Functor.Linear instead, as well as the IO
from System.IO.Linear 中的 pure
,因为 Prelude
的内容根本没有声明为线性的。
请注意,这个更简单的示例也无法编译:
sendToPeer :: Peer Idle %1-> IO (Peer Idle)
sendToPeer c = pure c
“没有 pure
”版本的问题对我来说很可疑,我认为这是一个错误,因为如果在参数级别完成模式匹配,它似乎可以工作:
sendToPeer :: Peer Idle %1-> Int -> Peer Busy
sendToPeer (Peer d) n = Peer d
您遇到了多个问题:
Prelude.pure
不是线性的。您需要在 linear-base
. 中使用来自 Control.Functor.Linear
的线性 Applicative
class 和相关方法函数 pure
Prelude.IO
不是线性的(即没有线性 Applicative
class 的实例)。您需要在 linear-base
. 中使用 System.IO.Linear
中的线性 IO
case
语句无法与当前的 LinearTypes
扩展一起正常工作。
关于最后一点,GHC 手册指出:
A case
expression may consume its scrutinee One
time, or Many
times. But the inference is still experimental, and may over-eagerly guess that it ought to consume the scrutinee Many
times.
linear-base
的用户指南比较直白。它包括一个标题为 Case statements are not linear 的部分,建议您不能将它们用于线性函数。
目前,如果您想保留 One
ness,则必须避免仔细检查带有 case
的表达式。
以下出现 type-check。我 认为 我已经按照推荐的方式设置了导入。请注意 Data.Functor.Linear
和 Control.Functor.Linear
中都有 pure
的版本,并且它们的工作方式不同。请参阅 documentation 顶部关于 Data.Functor.Linear
模块的注释。
{-# LANGUAGE LinearTypes #-}
module Lib where
import Prelude.Linear
import Control.Functor.Linear as Control
import qualified Prelude as NonLinear
import qualified System.IO.Linear as Linear
data Peer st = Peer String deriving Show
data Idle
data Busy
sendToPeer :: Peer Idle %1-> Int -> Linear.IO (Peer Busy)
sendToPeer (Peer d) n = Control.pure (Peer d)
我有一个非常简单的片段:
{-# LANGUAGE LinearTypes #-}
module Lib where
data Peer st = Peer { data :: String } deriving Show
data Idle
data Busy
sendToPeer :: Peer Idle %1-> Int -> IO (Peer Busy)
sendToPeer c n = case c of Peer d -> pure $ Peer d
我在 resolver: ghc-9.0.1
.
A function f is linear if: when its result is consumed exactly once, then its argument is consumed exactly once. Intuitively, it means that in every branch of the definition of f, its argument x must be used exactly once. Which can be done by
- Returning x unmodified
- Passing x to a linear function
- Pattern-matching on x and using each argument exactly once in the same fashion.
- Calling it as a function and using the result exactly once in the same fashion.
而我的函数 sendToPeer
正是这样做的 - 在 c
上进行模式匹配并且它的参数 d
使用一次 - 在 Peer d
中是线性的:
By default, all fields in algebraic data types are linear (even if -XLinearTypes is not turned on).
但是我得到一个错误:
• Couldn't match type ‘'Many’ with ‘'One’
arising from multiplicity of ‘c’
• In an equation for ‘sendToPeer’:
sendToPeer c n = case c of { Peer d -> pure $ Peer d }
|
11 | sendToPeer c n =
| ^
没有pure
:
sendToPeer :: Peer Idle %1-> Int -> Peer Busy
sendToPeer c n = case c of Peer d -> Peer d
但错误是一样的
使用 Control.Functor.Linear instead, as well as the IO
from System.IO.Linear 中的 pure
,因为 Prelude
的内容根本没有声明为线性的。
请注意,这个更简单的示例也无法编译:
sendToPeer :: Peer Idle %1-> IO (Peer Idle)
sendToPeer c = pure c
“没有 pure
”版本的问题对我来说很可疑,我认为这是一个错误,因为如果在参数级别完成模式匹配,它似乎可以工作:
sendToPeer :: Peer Idle %1-> Int -> Peer Busy
sendToPeer (Peer d) n = Peer d
您遇到了多个问题:
Prelude.pure
不是线性的。您需要在linear-base
. 中使用来自 Prelude.IO
不是线性的(即没有线性Applicative
class 的实例)。您需要在linear-base
. 中使用 case
语句无法与当前的LinearTypes
扩展一起正常工作。
Control.Functor.Linear
的线性 Applicative
class 和相关方法函数 pure
System.IO.Linear
中的线性 IO
关于最后一点,GHC 手册指出:
A
case
expression may consume its scrutineeOne
time, orMany
times. But the inference is still experimental, and may over-eagerly guess that it ought to consume the scrutineeMany
times.
linear-base
的用户指南比较直白。它包括一个标题为 Case statements are not linear 的部分,建议您不能将它们用于线性函数。
目前,如果您想保留 One
ness,则必须避免仔细检查带有 case
的表达式。
以下出现 type-check。我 认为 我已经按照推荐的方式设置了导入。请注意 Data.Functor.Linear
和 Control.Functor.Linear
中都有 pure
的版本,并且它们的工作方式不同。请参阅 documentation 顶部关于 Data.Functor.Linear
模块的注释。
{-# LANGUAGE LinearTypes #-}
module Lib where
import Prelude.Linear
import Control.Functor.Linear as Control
import qualified Prelude as NonLinear
import qualified System.IO.Linear as Linear
data Peer st = Peer String deriving Show
data Idle
data Busy
sendToPeer :: Peer Idle %1-> Int -> Linear.IO (Peer Busy)
sendToPeer (Peer d) n = Control.pure (Peer d)