Haskell Preludeを見ると、関数がある ことがわかりますconst
。
const x _ = x
この機能に関連するものを見つけることができないようです。
ポイントは何ですか?誰でもこの関数が使用される可能性のある場所の例を挙げられますか?
回答:
すべての柔軟性が必要ない場合に、高次関数に渡すのに役立ちます。たとえば、モナディックシーケンス演算子>>
は、モナディックバインド演算子に関して次のように定義できます。
x >> y = x >>= const y
ラムダを使うよりもすっきりしています
x >> y = x >>= \_ -> y
ポイントフリーでも使えます
(>>) = (. const) . (>>=)
この場合は特にお勧めしませんが。
map (const 42) [1..5]
その結果[42, 42, 42, 42, 42]
。
const
単一の引数に適用して、必要な場合に関数を生成するのに役立ちます(などへの受け渡しmap
)。
head = foldr const (error "Prelude.head: empty list")
hammarの優れた直接的な答えに追加するconst
と、のような控えめな関数は、SKI Combinator微積分で基本的であるのid
と同じ理由で、高次関数として非常に役立ちます。
Haskellのプレリュード関数は、その正式なシステムなどを意識してモデル化されたとは思いません。Haskellでリッチな抽象概念を作成するのは非常に簡単です。そのため、この種の理論的なものが実際に役立つものとして浮かび上がることがよくあります。
恥知らずなプラグが、私はのためのApplicativeのインスタンスがどのようにについてブログ(->)
実際にあるS
とK
コンビネータここでそれはあなたがにしているもののようなものだならば、。
((->) e)
と-また、読者のモナドであるReader
だけであることのようなnewtype
と-ラッパーask
関数があるid
ようだ、I
としてもコンビネータ。あなたは、HaskellのカレーのオリジナルBCKWベースで代わりに見ればB
、K
とW
しているfmap
、return
とjoin
それぞれ。
の簡単な使用例const
はData.Functor.(<$)
です。この関数を使用すると、次のように言うことができます。ここに何か退屈なファンクタがありますが、代わりに、ファンクタの形状を変更せずに、他の興味深いものを入れたいと思います。例えば
import Data.Functor
42 <$ Just "boring"
--> Just 42
42 <$ Nothing
--> Nothing
"cool" <$ ["nonsense","stupid","uninteresting"]
--> ["cool","cool","cool"]
定義は次のとおりです。
(<$) :: a -> f b -> f a
(<$) = fmap . const
または無意味に書かれていない:
cool <$ uncool = fmap (const cool) uncool
const
入力を「忘れる」ためにここでどのように使用されているかがわかります。
この機能に関連するものを見つけることができないようです。
他の回答の多くは、の比較的難解な(少なくとも初心者にとって)アプリケーションについて説明していconst
ます。これは単純なものですconst
。2つの引数を取り、最初の引数を破棄し、2番目の引数で何か面白いことをするラムダを取り除くために使用できます。
たとえば、以下の(非効率的ですが有益な)の実装length
、
length' = foldr (\_ acc -> 1 + acc) 0
次のように書き換えることができます
length' = foldr (const (1+)) 0
おそらくもっとエレガントです。
式const (1+)
は実際にはと意味的に同等\_ acc -> 1 + acc
です。これは、1つの引数を取り、それを破棄し、セクション を返すため(1+)
です。
別の用途は、評価されるべきではない仮引数(あいまいな型を解決するために使用される)を持つクラスメンバー関数を実装することです。Data.bitsの例:
instance Bits Int where
isSigned = const True
bitSize = const wordSize
...
constを使用することで、定数値を定義していることを明示的に言います。
個人的に私はダミーパラメータの使用が嫌いですが、それらがクラスで使用されている場合、これはインスタンスを作成するためのかなり良い方法です。
const
他の機能と組み合わせて探しているだけの実装かもしれません。これが私が発見した例です。
2タプルの構造を2タプルの別の構造に書き換えたいとします。私はこれを次のように表現するかもしれません:
((a,b),(c,d)) ⇒ (a,(c,(5,a)))
パターンマッチングを使用して簡単な定義を行うことができます。
f ((a,b),(c,d)) = (a,(c,(5,a)))
これらの種類の書き換えに対して無意味な(暗黙の)ソリューションが必要な場合はどうなりますか?後で考えたりいじったりする人もいますが、答えはで書き換えを表現できるということ(&&&), const, (.), fst, snd
です。注(&&&)
からですControl.Arrow
。
これらの関数を使用した例の解決策は次のとおりです。
(fst.fst &&& (fst.snd &&& (const 5 &&& fst.fst)))
との類似性に注意してください(a,(c,(5,a)))
。に置き換える&&&
と,
どうなりますか?次にそれを読み取ります:
(fst.fst, (fst.snd, (const 5, fst.fst)))
a
最初の要素の最初の要素がどのようになり、それがどのようにfst.fst
投影されるかに注意してください。c
2番目の要素の最初の要素がどのようになっているか、そしてそれがどのようにfst.snd
投影されるかに注意してください。つまり、変数はソースへのパスになります。
const
定数を導入することができます。名前がどのように意味と一致するか興味深いです!
あなたが無意味なスタイルで任意の関数を書くことができるように、私はその後、(限り、次のような機能として利用できるケース分析を持っているようにApplicativeでこのアイデアを一般化maybe
、either
、bool
)。繰り返しconst
ますが、定数を導入する役割を果たします。この作業はData.Function.Tacitパッケージで確認できます。
目標に向かって抽象的に開始し、実装に向けて取り組むと、その答えに驚くことができます。つまり、1つの関数は、マシンの1つの歯車のように神秘的である可能性があります。ただし、引き戻してマシン全体を表示すると、その歯車が必要なコンテキストを理解できます。
リストをローテーションしたいとします。これはHaskellでそうする慣用的な方法です:
rotate :: Int -> [a] -> [a]
rotate _ [] = []
rotate n xs = zipWith const (drop n (cycle xs)) xs
この関数は、関数を使用して2つの配列を圧縮します。const
最初の配列は無限巡回配列で、2番目は最初の配列です。
const
境界チェックとして機能し、元の配列を使用して巡回配列を終了します。
この機能に関連するものを見つけることができないようです。
与えられたリストのすべてのサブシーケンスを生成したいとします。
リスト要素ごとに、ある時点でTrue(現在のサブシーケンスに含める)またはFalse(含めない)を選択できます。これは、filterM関数を使用して行うことができます。
このような:
λ> import Control.Monad
λ> :t filterM
filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a]
λ>
たとえば、のすべてのサブシーケンスが必要[1..4]
です。
λ> filterM (const [True, False]) [1..4]
[[1,2,3,4],[1,2,3],[1,2,4],[1,2],[1,3,4],[1,3],[1,4],[1],[2,3,4],[2,3],[2,4],[2],[3,4],[3],[4],[]]
λ>
backgroundColor :: Text -> Color
自分用backgroundColor = const White