Haskell Preludeの「const」のポイントは何ですか?


92

Haskell Preludeを見ると、関数がある ことがわかりますconst

const x _ = x

この機能に関連するものを見つけることができないようです。

ポイントは何ですか?誰でもこの関数が使用される可能性のある場所の例を挙げられますか?


10
例:backgroundColor :: Text -> Color自分用backgroundColor = const White
Zhen

回答:


83

すべての柔軟性が必要ない場合に、高次関数に渡すのに役立ちます。たとえば、モナディックシーケンス演算子>>は、モナディックバインド演算子に関して次のように定義できます。

x >> y = x >>= const y

ラムダを使うよりもすっきりしています

x >> y = x >>= \_ -> y

ポイントフリーでも使えます

(>>) = (. const) . (>>=)

この場合は特にお勧めしませんが。


9
+1。また、パーサーコンビネーターを使用する場合にも頻繁に発生します。
Fred Foo

47
ああ、それはより「関数発生器」のようなものです-私はそれを1つの引数で使用し、常に定数値を返す関数(1つの引数を取る)を与えます。だから、map (const 42) [1..5]その結果[42, 42, 42, 42, 42]
stusmith 2009

2
stusmith:わかった。const単一の引数に適用して、必要な場合に関数を生成するのに役立ちます(などへの受け渡しmap)。
Conal、2011

8
@stusmith:あなたは、いくつかの興味深い方法でそれを使用することができます:head = foldr const (error "Prelude.head: empty list")
ホタルブクロ

27

hammarの優れた直接的な答えに追加するconstと、のような控えめな関数は、SKI Combinator微積分で基本的であるのidと同じ理由で、高次関数として非常に役立ちます。

Haskellのプレリュード関数は、その正式なシステムなどを意識してモデル化されたとは思いません。Haskellでリッチな抽象概念を作成するのは非常に簡単です。そのため、この種の理論的なものが実際に役立つものとして浮かび上がることがよくあります。

恥知らずなプラグが、私はのためのApplicativeのインスタンスがどのようにについてブログ(->)実際にあるSKコンビネータここでそれはあなたがにしているもののようなものだならば、。


8
まあ、SKIコンビネーターは確かにPreludeに影響を与えました。Sコンビネーターを含めるかどうかをJoe Faselと議論したことを覚えています。
8

4
ちなみに、((->) e)と-また、読者のモナドであるReaderだけであることのようなnewtypeと-ラッパーask関数があるidようだ、Iとしてもコンビネータ。あなたは、HaskellのカレーのオリジナルBCKWベースで代わりに見ればBKWしているfmapreturnjoinそれぞれ。
CAマッキャン2011

1
答えのブログリンクは死んでいます。それは今ここに指している必要があります:brandon.si/code/...を
nsxt

22

の簡単な使用例constData.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入力を「忘れる」ためにここでどのように使用されているかがわかります。


21

この機能に関連するものを見つけることができないようです。

他の回答の多くは、の比較的難解な(少なくとも初心者にとって)アプリケーションについて説明していconstます。これは単純なものですconst。2つの引数を取り、最初の引数を破棄し、2番目の引数で何か面白いことをするラムダを取り除くために使用できます。

たとえば、以下の(非効率的ですが有益な)の実装length

length' = foldr (\_ acc -> 1 + acc) 0

次のように書き換えることができます

length' = foldr (const (1+)) 0

おそらくもっとエレガントです。

const (1+)は実際にはと意味的に同等\_ acc -> 1 + accです。これは、1つの引数を取り、それを破棄し、セクション を返すため(1+)です。


4
これがどのように機能するかを理解するのに5分かかりました:)
Mukesh Soni

15

別の用途は、評価されるべきではない仮引数(あいまいな型を解決するために使用される)を持つクラスメンバー関数を実装することです。Data.bitsの例:

instance Bits Int where
  isSigned = const True
  bitSize  = const wordSize
  ...

constを使用することで、定数値を定義していることを明示的に言います。

個人的に私はダミーパラメータの使用が嫌いですが、それらがクラスで使用されている場合、これはインスタンスを作成するためのかなり良い方法です。


プロキシの引数は確かにはるかに優れており、最近のGHCをターゲットにすると、タイプアプリケーションがうまく機能します。
dfeuer

2

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投影されるかに注意してください。c2番目の要素の最初の要素がどのようになっているか、そしてそれがどのようにfst.snd投影されるかに注意してください。つまり、変数はソースへのパスになります。

const定数を導入することができます。名前がどのように意味と一致するか興味深いです!

あなたが無意味なスタイルで任意の関数を書くことができるように、私はその後、(限り、次のような機能として利用できるケース分析を持っているようにApplicativeでこのアイデアを一般化maybeeitherbool)。繰り返しconstますが、定数を導入する役割を果たします。この作業はData.Function.Tacitパッケージで確認できます。

目標に向かって抽象的に開始し、実装に向けて取り組むと、その答えに驚くことができます。つまり、1つの関数は、マシンの1つの歯車のように神秘的である可能性があります。ただし、引き戻してマシン全体を表示すると、その歯車が必要なコンテキストを理解できます。


2

Nothings文字列の長さに等しいリストを作成するとします。以下のようconstに戻り、最初の引数、ない第二の問題では、あなたが行うことができます。

listOfNothings :: String -> [Maybe Char]
listOfNothings = (map . const) Nothing

または、より明確に:

listOfNothing st = map (const Nothing) st

0

リストをローテーションしたいとします。これはHaskellでそうする慣用的な方法です:

rotate :: Int -> [a] -> [a] rotate _ [] = [] rotate n xs = zipWith const (drop n (cycle xs)) xs

この関数は、関数を使用して2つの配列を圧縮します。const最初の配列は無限巡回配列で、2番目は最初の配列です。

const 境界チェックとして機能し、元の配列を使用して巡回配列を終了します。

参照:Haskellでリストを回転する


0

この機能に関連するものを見つけることができないようです。

与えられたリストのすべてのサブシーケンスを生成したいとします。

リスト要素ごとに、ある時点で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],[]]
 λ> 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.