Haskell Prelude'deki 'const'ın anlamı nedir?


94

Haskell Prelude'a baktığımda bir işlev görüyorum const :

const x _ = x

Bu işlevle ilgili hiçbir şey bulamıyorum.

Amaç ne? Bu işlevin nerede kullanılabileceğine dair bir örnek verebilir misiniz?


10
Bir örnek: backgroundColor :: Text -> Colorbenim içinbackgroundColor = const White
Zhen

Yanıtlar:


84

Tüm esnekliklerine ihtiyacınız olmadığında daha yüksek dereceli işlevlere geçmek için kullanışlıdır. Örneğin, monadik sıra operatörü >>, monadik bağlama operatörü açısından şu şekilde tanımlanabilir:

x >> y = x >>= const y

Lambda kullanmaktan biraz daha temiz

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

ve hatta anlamsız olarak kullanabilirsiniz

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

bu durumda özellikle tavsiye etmiyorum.


9
+1. Ayrıştırıcı birleştiricileri kullanırken de sık sık ortaya çıkar.
Fred Foo

49
Ahh, bu daha çok bir 'işlev üreteci' - onu bir bağımsız değişkenle kullanıyorum ve bana her zaman sabit bir değer döndüren bir işlev veriyor (bir bağımsız değişken alarak). Yani map (const 42) [1..5]sonuçlanır [42, 42, 42, 42, 42].
stusmith

2
stusmith: Anladınız. consttek bir bağımsız değişkenin gerekli olduğu bir işlevi ('a iletme gibi map) elde etmek için kullanışlıdır .
Conal

9
@stusmith: Bunu bazı ilginç şekillerde kullanabilirsiniz:head = foldr const (error "Prelude.head: empty list")
rampion

27

Hammar en mükemmel doğrudan cevap eklemek için: mütevazi fonksiyonları gibi constve idbunlar aynı nedenden dolayı yüksek mertebeden fonksiyonu olarak gerçekten yararlı olan temel yılında KAYAK combinator hesabının .

Haskell'in başlangıç ​​işlevlerinin bilinçli olarak bu biçimsel sistem veya herhangi bir şeyden sonra modellendiğini düşünmüyorum. Haskell'de zengin soyutlamalar yaratmak çok kolaydır, bu nedenle bu tür teorik şeylerin pratik olarak yararlı olduğunu sıklıkla görürsünüz.

Utanmaz fiş, ancak Applicative örneğinin (->)aslında buradaS ve Kbirleştiriciler olduğu hakkında blog yazdım , eğer ilgilendiğiniz türden bir şeyse.


8
SKI birleştiricileri kesinlikle Prelude'u etkiledi. Joe Fasel ile S birleştiricinin dahil edilip edilmeyeceğini tartıştığımı hatırlıyorum.
augustss

4
Bu arada, ((->) e)aynı zamanda okuyucu monad - Readerve benzeri sadece newtypesarmalayıcıdır - ve o zaman askişlev id, yani Ibirleştirici de budur. Eğer Haskell Curry orijinal BCKW temelinde de yerine bakacak olursak, B, Kve Wvardır fmap, returnve joinsırasıyla.
CA McCann

1
Cevaptaki blog bağlantısı öldü. Şimdi burada işaret etmelidir: brandon.si/code/...
nsxt

23

Bu işlevle ilgili hiçbir şey bulamıyorum.

Diğer cevapların birçoğu ile ilgili görece ezoterik (en azından yeni gelen için) uygulamaları tartışıyor const. İşte basit bir tane: constiki argüman alan, birincisini atan ancak ikinciyle ilginç bir şey yapan bir lambdadan kurtulmak için kullanabilirsiniz .

Örneğin, aşağıdaki (verimsiz ama öğretici) uygulama length,

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

olarak yeniden yazılabilir

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

bu belki daha zariftir.

İfade const (1+)aslında anlamsal olarak eşdeğerdir \_ acc -> 1 + acc, çünkü bir argüman alır, onu atar ve bölümü döndürür (1+).


5
Bu :) nasıl çalıştığını anlamak için 5 dakika götürdü
Mukesh Soni

22

Kullanmak için basit bir örnek constolup Data.Functor.(<$). Bu işlevle şunu söyleyebilirsiniz: Burada sıkıcı bir şey olan bir işlevim var, ama bunun yerine, işlevin şeklini değiştirmeden içinde başka bir ilginç şey olmasını istiyorum. Örneğin

import Data.Functor

42 <$ Just "boring"
--> Just 42

42 <$ Nothing
--> Nothing

"cool" <$ ["nonsense","stupid","uninteresting"]
--> ["cool","cool","cool"]

Tanım şu şekildedir:

(<$) :: a -> f b -> f a
(<$) =  fmap . const

veya anlamsız olarak yazılmamış:

cool <$ uncool =  fmap (const cool) uncool

constBurada girdiyi "unutmak" için nasıl kullanıldığını görüyorsunuz .


15

Diğer bir kullanım, değerlendirilmemesi gereken (belirsiz türleri çözmek için kullanılan) bir kukla bağımsız değişkeni olan sınıf üyesi işlevleri uygulamaktır. Data.bits içinde olabilecek örnek:

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

Const kullanarak, sabit değerler tanımladığımızı açıkça söylüyoruz.

Şahsen ben kukla parametrelerin kullanımından hoşlanmıyorum, ancak bir sınıfta kullanılıyorsa, bu örnek yazmanın oldukça güzel bir yoludur.


Proxy argümanları gerçekten çok daha iyidir ve yeni GHC'yi hedeflerken, tür uygulamaları hile yapar.
dfeuer

2

constsadece diğer işlevlerle birlikte aradığınız uygulama olabilir. İşte keşfettiğim bir örnek.

Diyelim ki 2-demetlik bir yapıyı başka bir 2-demet yapıya yeniden yazmak istiyoruz. Bunu şu şekilde ifade edebilirim:

((a,b),(c,d)) ⇒ (a,(c,(5,a)))

Örüntü eşleme ile basit bir tanım verebilirim:

f ((a,b),(c,d)) = (a,(c,(5,a)))

Ya bu tür yeniden yazmalar için anlamsız (zımni) bir çözüm istersem? Bazıları daha sonra düşünür ve uğraşır, cevap, herhangi bir yeniden yazımı ifade edebileceğimizdir (&&&), const, (.), fst, snd. (&&&)Kimden olduğuna dikkat edin Control.Arrow.

Bu fonksiyonları kullanan örneğin çözümü:

(fst.fst &&& (fst.snd &&& (const 5 &&& fst.fst)))

İle benzerliğe dikkat edin (a,(c,(5,a))). Ya &&&ile değiştirirsek ,? Sonra okur:

(fst.fst, (fst.snd, (const 5, fst.fst)))

Dikkat edin a, ilk unsurun ilk unsuru ve fst.fstprojelendirme budur. Dikkat edin c, ikinci unsurun ilk unsuru nasıldır ve fst.sndprojelendirme budur. Yani değişkenler, kaynaklarına giden yol haline gelir.

constsabitleri tanıtmamıza izin verir. İsmin anlamla uyuşması ilginç!

Eğer bir anlamsız bir tarzda herhangi bir işlev yazabilirsiniz böylece Sonra (çok uzun gibi işlevler gibi vaka analizi mevcut olduğu gibi uygulamalı ile bu fikri genelleştirilmiş maybe, either, bool). Yine, constsabitleri tanıtma rolünü oynar. Bu çalışmayı Data.Function.Tacit paketinde görebilirsiniz.

Soyut olarak, hedefe başladığınızda ve sonra bir uygulamaya doğru çalıştığınızda, cevaplar sizi şaşırtabilir. Yani, herhangi bir işlev, bir makinedeki herhangi bir dişli kadar gizemli olabilir. Bununla birlikte, tüm makineyi ortaya çıkarmak için geri çekerseniz, o çarkın gerekli olduğu bağlamı anlayabilirsiniz.


2

NothingsBir dizenin uzunluğuna eşit bir liste oluşturmak istediğinizi varsayalım. Gibi constdöner ilk argüman, hiçbir saniyesini önemi, yapabileceğiniz:

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

veya daha açık bir şekilde:

listOfNothing st = map (const Nothing) st

0

Bir listeyi döndürmek istediğinizi söyleyin. Bu, Haskell'de bunu yapmanın deyimsel bir yoludur:

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

Bu işlev, iki diziyi işlevle sıkıştırır const; ilki sonsuz döngüsel dizidir, ikincisi ise başladığınız dizidir.

const sınır kontrolü görevi görür ve döngüsel diziyi sonlandırmak için orijinal diziyi kullanır.

Bakınız: Haskell'de bir listeyi döndürme


0

Bu işlevle ilgili hiçbir şey bulamıyorum.

Verilen bir listenin tüm alt dizilerini oluşturmak istediğinizi varsayalım.

Her liste öğesi için, belirli bir noktada Doğru (mevcut alt diziye dahil edin) veya Yanlış (dahil etmeyin) seçenekleriniz vardır. Bu, filterM işlevi kullanılarak yapılabilir .

Bunun gibi:

 λ> import Control.Monad
 λ> :t filterM
 filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a]
 λ> 

Örneğin, tüm alt dizilerini istiyoruz [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],[]]
 λ> 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.