하스켈 골프에 대한 일반적인 팁은 무엇입니까? 나는 Haskell에게 다소 특정한 코드 골프 문제에 적용될 수있는 아이디어를 찾고 있습니다. 답변 당 하나의 팁만 게시하십시오.
Haskell에서 골프를 처음 사용하는 경우 Haskell의 골프 규칙 안내서를 참조하십시오 . Haskell 전용 채팅방이 있습니다 : Of Monads and Men .
하스켈 골프에 대한 일반적인 팁은 무엇입니까? 나는 Haskell에게 다소 특정한 코드 골프 문제에 적용될 수있는 아이디어를 찾고 있습니다. 답변 당 하나의 팁만 게시하십시오.
Haskell에서 골프를 처음 사용하는 경우 Haskell의 골프 규칙 안내서를 참조하십시오 . Haskell 전용 채팅방이 있습니다 : Of Monads and Men .
답변:
이는 일반적으로 정의 또는 호출 당 하나 또는 두 개의 공간을 절약합니다.
0!(y:_)=y
x!(y:z)=(x-1)!z
vs.
f 0(y:_)=y
f x(y:z)=f(x-1)z
1 바이트 사업자에 사용할 수있는 기호는 !
, #
, %
, &
,와 ?
. 다른 모든 ASCII 문장 부호는 Prelude에 의해 연산자로 이미 정의되어 $
있거나 (예 :) Haskell의 구문에 특별한 의미가 있습니다 (예 :) @
.
5 개 이상의 연산자가 필요한 경우 위와 같은 위의 조합 !#
또는 다음과 같은 특정 유니 코드 문장 부호 문자 (UTF-8의 2 바이트)를 사용할 수 있습니다.
¡ ¢ £ ¤ ¥ ¦ § ¨ © ¬ ® ¯ ° ± ´ ¶ · ¸ ¿ × ÷
(x!y)z=x+y*z
그리고 (x#y)z u=x*z+y*u
둘 다 예상대로 작동합니다.
\f g(!)x y->f g!x y
대신\f g j x y->j(f g)(x y)
g x=…;g(f x)
보다 긴_?x=…;0!f x
빠른 검토 :
xs >> ys = concat $ replicate (length xs) ys
xs >>= f = concatMap f xs
mapM id[a,b,c] = cartesian product of lists: a × b × c
mapM f[a,b,c] = cartesian product of lists: f a × f b × f c
예 :
Prelude> "aa">>[1..5]
[1,2,3,4,5,1,2,3,4,5]
concatMap
Prelude> reverse=<<["Abc","Defgh","Ijkl"]
"cbAhgfeDlkjI"
concat
+ 목록 이해Prelude> do x<-[1..5];[1..x]
[1,1,2,1,2,3,1,2,3,4,1,2,3,4,5]
Prelude> mapM id["Hh","io",".!"]
["Hi.","Hi!","Ho.","Ho!","hi.","hi!","ho.","ho!"]
Prelude> mapM(\x->[0..x])[3,2]
[[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2],[3,0],[3,1],[3,2]]
[0..b]>>[a]
입니다 replicate a b
.
a<$[1..b]
는 더 짧습니다 replicate
.
=<<
하면 가져옵니다 Control.Monad
. 다른 이유로 필요하지 않은 경우 인수를 바꾸고 사용하는 >>=
것이 더 간결 해 보입니다.
Data.Traversable
어쨌든 필요한 경우 직교 곱 예제를로 줄일 수 있습니다 for["Hh","io",".!"]id
.
조건부가 아닌 경비원을 사용하십시오.
f a=if a>0 then 3 else 7
g a|a>0=3|True=7
들여 쓰기가 아닌 세미콜론 사용
f a=do
this
that
g a=do this;that
부울 함수에 부울 표현식 사용
f a=if zzz then True else f yyy
g a=zzz||f yyy
(SO는 이것을 별도로 게시하는 데 어려움을 겪고 있습니다)
&&
목록 이해 안에있을 때 대신 여러 보호대를 사용 하십시오.
True
=>1>0
f a=if a>0 then 3 else 7
이 내용을 담은 GHC의 첫 번째 버전은 2015 년 3 월 27 일 에 발표되었습니다 .
최신 버전이며 Prelude는 골프에 유용한 새로운 기능을 추가했습니다.
(<$>)
및 (<*>)
운영이 유용한 연산자 Data.Applicative
는 그것을 만들었습니다! <$>
그냥 fmap
당신이 교체 할 수 있도록, map f x
그리고 fmap f x
함께 f<$>x
사방 바이트를 다시 승리. 또한 목록 <*>
의 Applicative
인스턴스 에서 유용 합니다.
Prelude> (,)<$>[1..2]<*>"abcd"
[(1,'a'),(1,'b'),(1,'c'),(1,'d'),(2,'a'),(2,'b'),(2,'c'),(2,'d')]
(<$)
연산자x<$a
동등하다 fmap (const x) a
; 즉, 컨테이너의 모든 요소를로 바꿉니다 x
.
이것 보다 좋은 대안이 종종있다 replicate
: 4<$[1..n]
보다 짧다 replicate n 4
.
다음 기능은 목록 작업에서 [a]
일반 Foldable
유형 으로 해제되었습니다 t a
.
fold*, null, length, elem, maximum, minimum, sum, product
and, or, any, all, concat, concatMap
즉, 이제 Maybe a
"최대 하나의 요소가있는 목록"처럼 동작하는 작업도 수행합니다 . 예를 들어, null Nothing == True
또는 sum (Just 3) == 3
. 마찬가지로 값으로 length
0을 Nothing
, Just
값으로 1을 반환 합니다. 쓰는 대신 쓸 x==Just y
수 있습니다 elem y x
.
튜플에도 적용 할 수 있으며, \(a, b) -> [b]
처음 호출 한 것처럼 작동합니다 . 그것은 거의 완전히 쓸모하지만 or :: (a, Bool) -> Bool
이상의 문자 짧은 snd
, 그리고 elem b
보다 짧다 (==b).snd
.
mempty
과mappend
종종 생명의 은인은 아니지만 유형을 추론 할 수 있다면 mempty
1 바이트보다 짧습니다 Nothing
.
<*>
Prelude로 만드는 것이 좋습니다 ! 코드 골프가 아닌 경우에도 유용합니다 (응용 프로그램은 그렇게 긴 단어입니다).
[1..2]
. 그건 그냥[1,2]
<*
에서 Applicative
목록에 대한 인 xs <* ys == concatMap (replicate (length ys)) xs
. 이것은 다른 xs >> ys
나 xs *> ys
있는 것입니다 concat (replicate (length ys)) xs
. 이 시점에서도 pure
더 짧은 것이 었 return
습니다.
<>
대신 mappend
GHC 8.4.1 사용)의 일부를 사용할 수 있습니다 Prelude
.
사용 1<2
대신 True
하고 1>2
대신 False
.
g x|x<10=10|True=x
f x|x<10=10|1<2=x
f=max 10
.
if(true)
다른 언어로 작성 되었습니다. 전주곡에서 그렇지 않으면 실제로는 부울 값 True
입니다.
otherwise
.
누구나 자신이 유용한 구문이며, 종종 map
람다 보다 짧은 것을 알고 있습니다 .
Prelude> [[1..x]>>show x|x<-[1..9]]
["1","22","333","4444","55555","666666","7777777","88888888","999999999"]
또는 filter
(선택적으로 map
동시에) :
Prelude> [show x|x<-[1..60],mod 60x<1]
["1","2","3","4","5","6","10","12","15","20","30","60"]
그러나 몇 가지 이상한 용도가 있습니다. 예를 들어, 목록 이해에는 <-
화살표 가 전혀 필요하지 않습니다 .
Prelude> [1|False]
[]
Prelude> [1|True]
[1]
대신에을 if p then[x]else[]
쓸 수 있습니다 [x|p]
. 또한 조건을 만족하는 목록의 요소 수를 계산하려면 다음과 같이 직관적으로 작성하십시오.
length$filter p x
그러나 이것은 더 짧습니다.
sum[1|y<-x,p y]
Prelude
GHCi를 시작하고 Prelude 문서를 스크롤하십시오 . 짧은 이름을 가진 함수를 교차 할 때마다 유용 할 수있는 경우를 찾기 위해 돈을 지불 할 수 있습니다.
예를 들어 문자열 s = "abc\ndef\nghi"
을 공백으로 구분 된 문자열 로 변환한다고 가정합니다 "abc def ghi"
. 확실한 방법은 다음과 같습니다.
unwords$lines s
그러나 당신은 당신이 남용하면 더 잘 할 수있는 max
, 그리고 그 사실을 \n < space < printable ASCII
:
max ' '<$>s
또 다른 예는 lex :: String -> [(String, String)]
매우 신비한 일입니다.
Prelude> lex " some string of Haskell tokens 123 "
[("some"," string of Haskell tokens 123 ")]
시도 fst=<<lex s
공백을 건너 뛰는, 문자열에서 첫 번째 토큰을 얻을 수 있습니다. 여기서 사용하여 henkma 영리한 해결책 lex.show
에 Rational
값.
리스트 이해는 상수에서 패턴 일치를 할 수 있습니다.
[0|0<-l]
이것은리스트의 0을 추출합니다 l
. 즉,의 수만큼 0의리스트를 만듭니다 l
.
[1|[]<-f<$>l]
이것은 많은 목록을 만드는 1
요소가 있기 때문에 's의 l
그 f
(사용하여 빈리스트에 소요 <$>
중위로 map
). sum
이러한 요소를 세려면 적용하십시오 .
비교:
[1|[]<-f<$>l]
[1|x<-l,f x==[]]
[x|(0,x)<-l]
상수는 패턴 일치의 일부로 사용될 수 있습니다. 첫 번째 항목이 인 모든 튜플의 두 번째 항목을 추출합니다 0
.
이들 모두 변수의 값이 아닌 실제 상수 리터럴이 필요합니다. 예를 들어 외부 바인딩을 덮어 쓰므로 , not let x=1 in [1|x<-[1,2,3]]
이 출력됩니다 .[1,1,1]
[1]
x
words
긴 문자열 목록 대신 사용하십시오 . 이것은 실제로 Haskell에만 국한된 것이 아니며 다른 언어도 비슷한 속임수를 가지고 있습니다.
["foo","bar"]
words"foo bar" -- 1 byte longer
["foo","bar","baz"]
words"foo bar baz" -- 1 byte shorter
["foo","bar","baz","qux"]
words"foo bar baz qux" -- 3 bytes shorter
1)를
사용하여 모나 딕 함수를 시뮬레이션합니다 mapM
.
코드는 여러 번 가질 sequence(map f xs)
수 있지만로 대체 될 수 있습니다 mapM f xs
. sequence
혼자 사용하는 경우에도 길어집니다 mapM id
.
2)
이용하여 기능을 결합 (>>=)
(또는 (=<<)
)
함수 모나드 버전 (>>=)
은 다음과 같이 정의됩니다.
(f >>= g) x = g (f x) x
파이프 라인으로 표현할 수없는 함수를 만드는 데 유용 할 수 있습니다. 예를 들어, \x->x==nub x
보다 긴 nub>>=(==)
, 그리고 \t->zip(tail t)t
이상이다 tail>>=zip
.
Applicative
하지 Monad
의 구현있어 pure
보다 짧은뿐만 아니라이 const
실제로 이전에 저를 도왔다.
나는 방금 henkma에 의해 매우 호기심 많은 방법으로 outgolfed했습니다 .
f
응답 의 보조 함수 가 응답의 다른 곳에서 사용되지 않고 f
한 번 호출 된 연산자를 사용하는 경우 연산자를 인수로 지정하십시오 f
.
이:
(!)=take
f a=5!a++3!a
reverse.f
이보다 2 바이트 더 깁니다.
f(!)a=5!a++3!a
reverse.f take
목록을 연결할 때 첫 번째 길이가 1이면 :
대신 사용하십시오.
a++" "++b
a++' ':b -- one character shorter
[3]++l
3:l -- three characters shorter
1:2:3:x
:) [1,2,3]++x
.
백틱을 너무 자주 사용하지 마십시오. 백틱은 접두사 기능의 섹션을 만들기위한 유용한 도구이지만 잘못 사용되기도합니다.
누군가이 하위 표현식을 작성하는 것을 보았습니다.
(x`v`)
그것은 단지와 동일하지만 v x
.
또 다른 예는 (x+1)`div`y
와는 반대로 글을 쓰는 것 div(x+1)y
입니다.
나는 주위에 일을 참조 div
하고 elem
이러한 기능은 일반적으로 일반 코드에서 중위로 사용되기 때문에 더 자주.
let
정의하는 함수의 인수를 해체하는 람다 또는 람다 보다 짧습니다 . 당신이 뭔가해야 할 때 도움이 fromJust
에서를 Data.Maybe
:
f x=let Just c=… in c
보다 길다
f x=(\(Just c)->c)$…
보다 길다
m(Just c)=c;f x=m$…
보다 길다
f x|Just c<-…=c
실제로, 그것들은 해체하는 대신 평범한 오래된 값을 바인딩 할 때도 짧습니다 : xnor 's tip 참조하십시오 .
e
는 실제로 하나의 토큰이 아니라 $
이전 에 필요한 더 긴 표현식 이라고 가정 합니다.이 경우 일반적입니다.
last$x:[y|b]
에 해당
if b then y else x
작동 방식은 다음과 같습니다.
[y|b] x:[y|b] last$x:[y|b]
if... +--------------------------------
b == False | [] [x] x
b == True | [y] [x,y] y
if b then y else x
?
bool
목록 이해가 필요하지 않으므로 더 짧게 사용 하지 않겠
빼기 부호 -
는 많은 구문 규칙에서 성가신 예외입니다. 이 팁에는 Haskell에서 부정과 뺄셈을 표현하는 몇 가지 간단한 방법이 나와 있습니다. 내가 놓친 부분이 있으면 알려주십시오.
e
그냥하세요 -e
. 예를 들어, -length[1,2]
gives -2
.e
도 적당히 복잡, 당신은 주위에 괄호가 필요합니다 e
,하지만 당신은 일반적으로 주위를 이동하여 바이트를 저장할 수 있습니다 -length(take 3 x)
보다 짧습니다 -(length$take 3 x)
.e
앞에는 =
의 중위 연산자 또는 정착 미만 6 이상, 당신은 공간이 필요 : f= -2
정의 f
및 k< -2
테스트를하는 경우 k
보다 작다 -2
. 고 정성이 6 이상이면 parens : 2^^(-2)
gives 가 필요 합니다 0.25
. 당신은 일반적으로 이러한 없애 물건을 다시 정렬 할 수 있습니다 : 예를 들어, 할 -k>2
대신 k< -2
.!
연산자 인 경우 고 정성이 최대 6 인 -a!b
것처럼 구문 분석되고 (따라서 제공 ) 그렇지 않으면 (그렇게 제공합니다 ). 사용자 정의 연산자와 역틱 된 함수의 기본 고정도는 9이므로 두 번째 규칙을 따릅니다.(-a)!b
!
-1<1
True
-(a!b)
-[1,2]!!0
-1
map
등과 함께 사용하기 위해) 섹션을 사용하십시오 (0-)
.k
하는 섹션을 사용하십시오 . 꽤 복잡한 표현 일 수도 있습니다 : 예상대로 작동합니다.(-k+)
-k
k
(-2*length x+)
pred
양쪽에 공백이 필요하지 않으면 대신 사용하십시오 . 이것은 드문 일반적으로 발생 until
하기 때문에, 또는 사용자 정의 함수 map pred x
로 대체 될 수 pred<$>x
와 iterate pred x
로 [x,x-1..]
. 그리고 f pred x
어딘가에 있다면 f
어쨌든 infix 함수로 정의해야 합니다. 이 팁을 참조하십시오 .함수 정의에서 패턴 일치 사례의 순서를 변경하여 몇 바이트를 저장할 수도 있습니다. 이러한 절감 효과는 저렴하지만 간과하기 쉽습니다.
예를 들어, 이 답변 의 다음 이전 버전 (일부)을 고려하십시오 .
(g?x)[]=x
(g?x)(a:b)=g(g?x$b)a
이는 ?
기본 사례가 빈 목록 인의 재귀 적 정의입니다 . 때문에 []
유용한 값이 아닌, 우리는 정의를 교환하고 와일드 카드로 교체해야 _
하거나 더미 인수 y
바이트를 저장 :
(g?x)(a:b)=g(g?x$b)a
(g?x)y=x
같은 대답에서 다음 정의를 고려하십시오.
f#[]=[]
f#(a:b)=f a:f#b
빈 목록은 반환 값에 발생하므로 사례를 교체하여 2 바이트를 절약 할 수 있습니다.
f#(a:b)=f a:f#b
f#x=x
또한 함수 인수의 순서는 불필요한 공백을 제거하여 때때로 차이를 만들 수 있습니다. 이 답변 의 이전 버전을 고려하십시오 .
h p q a|a>z=0:h p(q+2)(a-1%q)|1<2=1:h(p+2)q(a+1%p)
첫 번째 분기 사이 h
와 p
첫 분기 사이에 성가신 공백이 있습니다. h a p q
대신 다음을 정의하여 제거 할 수 있습니다 h p q a
.
h a p q|a>z=0:h(a-1%q)p(q+2)|1<2=1:h(a+1%p)(p+2)q
포괄의 최종 가드 True
(짧은 등은 1>0
) 변수를 결합 할 수 있습니다. 비교:
... |1>0=1/(x+y)
... |z<-x+y=1/z
... |1>0=sum l-sum m
... |s<-sum=s l-s m
경비원은 필수적이며 그렇지 않으면 낭비되기 때문에 이것을 가치있게하는 데 필요한 것은 거의 없습니다. 한 쌍의 Parens를 저장하거나 두 번 사용되는 길이 3 표현식을 바인딩하는 것으로 충분합니다. 때로는 마지막 사례를 바인딩을 가장 잘 사용하는 표현으로 만들기 위해 경비원을 부정 할 수 있습니다.
때로는 로컬 함수 또는 연산자를 정의해야하지만 추가 인수를 추가 하여 작성 where
하거나 let…in
최상위 레벨로 올리 려면 많은 바이트가 필요합니다.
g~(a:b)=2!g b where k!l=k:take(a-1)l++(k+1)!drop(a-1)l
g~(a:b)=let k!l=k:take(a-1)l++(k+1)!drop(a-1)l in 2!g b
g~(a:b)=2!g b$a;(k!l)a=k:take(a-1)l++((k+1)!drop(a-1)l)a
다행스럽게도 Haskell은 혼란스럽고 거의 사용되지 않았지만 로컬 선언에 대한 합리적으로 간결한 구문을 가지고 있습니다 .
fun1 pattern1 | let fun2 pattern2 = expr2 = expr1
이 경우 :
g~(a:b)|let k!l=k:take(a-1)l++(k+1)!drop(a-1)l=2!g b
이 구문을 다중 문 선언 또는 여러 선언과 함께 사용할 수 있으며 중첩도 가능합니다.
fun1 pattern1 | let fun2 pattern2 = expr2; fun2 pattern2' = expr2' = expr1
fun1 pattern1 | let fun2 pattern2 = expr2; fun3 pattern3 = expr3 = expr1
fun1 pattern1 | let fun2 pattern2 | let fun3 pattern3 = expr3 = expr2 = expr1
변수 또는 다른 패턴을 바인딩하는 데에도 작동하지만 함수를 바인딩하지 않으면 패턴 가드 가 짧아지는 경향이 있습니다.
[f 1|let f x=x+1]
.
repeat n
-- 8 bytes, whitespace might be needed before and after
repeat n
-- 8 bytes, whitespace might be needed before
cycle[n]
-- 7 bytes, whitespace might be needed before and after, can be reused,
-- needs an assignment, n needs to be global
l=n:l;l
-- 7 bytes, never needs whitespace, n needs to derive from Enum,
-- n has to be short enough to be repeated twice
[n,n..]
이 네 가지 표현 중 하나가 무한한 목록을 생성합니다 n
.
매우 구체적인 팁이지만 최대 3 바이트 를 절약 할 수 있습니다 !
n
전역 인 경우 l=n:l;l
길이가 같고 (일부) 더 긴 표현식에서 작동합니다. (하지만 공백이 필요할 수 있습니다.)
일부 condition에 따라 목록 A
또는 빈 목록 을 반환하는 조건이 필요한 경우 일반적인 조건부 구문에 대한 짧은 대안이 있습니다.[]
C
if(C)then(A)else[] -- the normal conditional
last$[]:[A|C] -- the golfy all-round-conditional
concat[A|C] -- shorter and works when surrounded by infix operator
id=<<[A|C] -- even shorter but might conflict with other infix operators
[x|C,x<-A] -- same length and no-conflict-guarantee™
[0|C]>>A -- shortest way, but needs surrounding parenthesis more often than not
A
하고 []
스위치.
*>
보다 높은 고정력을가집니다 >>
.
람다 표현에는 실제로 괄호가 필요하지 않습니다. 단지 탐욕스럽게 모든 것을 잡고 있으므로 모든 것이 여전히 구문 분석됩니다.
(foo$ \x -> succ x)
let a = \x -> succ x in a 4
main = getContents>>= \x -> head $ words x
이 발생하면 1 ~ 2 바이트를 절약 할 수있는 이상한 경우가 있습니다. 나는 \
또한 연산자를 정의하는 데 사용될 수 있다고 생각 하므로 이것을 악용 할 때 연산자 바로 뒤에 람다를 작성할 때 공간이 필요합니다 (예 : 세 번째 예).
람다를 사용하는 것이 내가 알아낼 수있는 가장 짧은 곳 의 예 입니다. 코드는 기본적으로 다음과 같습니다.
a%f=...
f t=sortBy(% \c->...)['A'..'Z']
let
람다로 교체일반적으로 가드와 바인딩 되거나 어떤 이유로 든 전역 적으로 정의 될 수없는 고독한 보조 정의를 단축 할 수 있습니다 . 예를 들어, 교체
let c=foo a in bar
3 바이트 짧게
(\c->bar)$foo a
여러 보조 정의의 경우 정의 수에 따라 게인이 더 작을 수 있습니다.
let{c=foo a;n=bar a}in baz
(\c n->baz)(foo a)$bar a
let{c=foo a;n=bar a;m=baz a}in qux
(\c n m->qux)(foo a)(bar a)$baz a
let{c=foo a;n=bar a;m=baz a;l=qux a}in quux
(\c n m l->quux)(foo a)(bar a)(baz a)$qux a
일부 정의가 다른 정의를 참조하면 다음과 같이 바이트를 저장하기가 더 어렵습니다.
let{c=foo a;n=bar c}in baz
(\c->(\n->baz)$bar c)$foo a
이것에 대한 주요 경고는 let
@ChristianSievers가 지적한 것처럼 다형성 변수를 정의 할 수 있지만 람다는 그렇지 않습니다. 예를 들어
let f=length in(f["True"],f[True])
결과는 (1,1)
되지만
(\f->(f["True"],f[True]))length
유형 오류가 발생합니다.
let
있으므로 할 수 있습니다 let f=id in (f 0,f True)
. 우리가 이것을 lambda로 다시 쓰려고 시도하면 check를 입력하지 않습니다.
명명 된 함수를 정의 할 때 표현식을 가드의 변수에 바인딩 할 수 있습니다. 예를 들어
f s|w<-words s=...
와 동일
f s=let w=words s in ...
f s=(\w->...)$words s
반복 표현식을 저장하려면 이것을 사용하십시오. 식을 두 번 사용하면 간격과 우선 순위 문제로 인해 길이가 6 일 때도 끊어집니다.
(이 예에서 원래 변수 s
를 사용하지 않으면 수행하는 것이 더 짧습니다
g w=...
f=g.words
그러나 더 복잡한 표현식을 바인딩하는 것은 사실이 아닙니다.)
Just
예제는 패턴 일치가 표현식에 저장하는 것이 아니라 컨테이너에서 추출하는 것이라고 생각하게했습니다.
(0<$)
대신 사용length
목록 a
이 목록 보다 긴 경우 테스트 할 때 b
일반적으로
length a>length b
그러나 두 목록의 각 요소를 같은 값으로 바꾸고 예를 들어 0
두 목록을 비교하는 것이 더 짧을 수 있습니다.
(0<$a)>(0<$b)
괄호 때문에 필요 <$
하고, 비교 연산자 ( ==
, >
, <=
다른 경우에 그들이 필요하지 않을 수도 있지만 ...)가 더 바이트를 절약, 같은 우선 순위 레벨 4를 가지고있다.
scanr(:)[]
목록의 접미사를 얻는 데 사용하십시오 .
λ scanr(:)[] "abc"
["abc","bc","c",""]
이것은 tails
이후 보다 훨씬 짧습니다 import Data.List
. scanr(\_->init)=<<id
(Ørjan Johansen이 만든) 접두사를 사용할 수 있습니다 .
λ scanr(\_->init)=<<id $ "abc"
["","a","ab","abc"]
이것은 바이트를 절약합니다
scanl(\s c->s++[c])[]
scanl(flip(:))[] "abc"
= ["","a","ba","cba"]
도 언급 할 가치가 있습니다. 때로는 접두사가 거꾸로되는 것이 중요하지 않습니다.
scanr(\_->init)=<<id