非常にシンプルなスニペットがあります:
{-# 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
。
からドキュメンテーション:
関数fが線形であるとは、その結果が1回だけ使用される場合、その引数も1回だけ使用されるという条件です。直感的には、fの定義のどの分岐でも、引数xは1回だけ使用されなければならないことを意味します。これは次のように行うことができます。
- x を変更せずに返す
- xを線形関数に渡す
- x に対してパターン マッチングを行い、各引数を同じ方法で 1 回だけ使用します。
- これを関数として呼び出し、同じ方法で結果を 1 回だけ使用します。
そして私の関数はsendToPeer
まさにこれを実行します - パターンマッチを行いc
、その引数はd
1 回使用されます - はPeer d
線形です:
デフォルトでは、代数データ型のすべてのフィールドは線形です (-XLinearTypes がオンになっていない場合でも)。
しかしエラーが発生しました:
• 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
しかし、エラーは同じです。
ベストアンサー1
次のような複数の問題に直面しています:
Prelude.pure
は線形ではありません。 のlinearクラスApplicative
と関連メソッド関数を使用する必要があります。pure
Control.Functor.Linear
linear-base
Prelude.IO
は線形ではありません (つまり、線形クラスのインスタンスを持っていません)。のからApplicative
linear を使用する必要があります。IO
System.IO.Linear
linear-base
- (GHC バージョン 9.2 より前)
case
ステートメントは、現在の拡張機能では正しく機能しませんでしたLinearTypes
。
最後の点に関して、GHC マニュアルには次のように記載されています。
表現
case
は、その精査One
時間を、あるいはMany
何回も消費する場合があります。しかし、推論は依然として実験的なものであり、精査Many
時間を消費するはずだと過度に熱心に推測する可能性があります。
のユーザーズガイドはlinear-base
もっと率直です。そこには、ケース文は線形ではないこれは、線形関数には使用できないことを示唆しています。
case
現時点では、式の性質を保持したい場合は、を使用した式の精査を避ける必要がありますOne
。GHC バージョン 9.2 以降では、この回避策は不要になりました。
以下は型チェックされているようです。考えるインポートは推奨された方法で設定しました。とpure
の両方にのバージョンがあり、動作が異なることに注意してください。Data.Functor.Linear
Control.Functor.Linear
ドキュメンテーションモジュール用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)