/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ import * as Maybe from './maybe' ; enum ListType { nil , cons } export class List < T > { private listType : ListType ; private value ? : T ; private next ? : List < T > ; constructor ( listType , value ? , next ? ) { this . listType = listType ; this . value = value ; this . next = next ; } match < U > ( nil , cons ) { switch ( this . listType ) { case ListType . nil : return nil ( ) ; case ListType . cons : return cons ( this . value ! , this . next ! ) ; } } } export function of < T > ( ... args ) { if ( args . length === 0 ) { return new List < T > ( ListType . nil ) ; } else { var list = new List < T > ( ListType . nil ) ; for ( var i = args . length - 1 ; i >= 0 ; i -- ) { list = cons ( args [ i ] , list ) ; } return list ; } } function returnTrue ( ) { return true ; } function returnFalse ( ) { return false ; } export function isEmpty < T > ( list ) { return list . match ( returnTrue , returnFalse ) ; } export function length < T > ( list ) { return list . match ( function ( ) { return 0 ; } , function ( val , next ) { return 1 + length ( next ) ; } ) ; } export function cons < T > ( elem , list ) { return new List < T > ( ListType . cons , elem , list ) ; } function returnJustHead < T > ( val , tail ) { return val ; } export function head < T > ( list ) { return list . match ( function ( ) { return null ; } , returnJustHead ) ; } function returnTail < T > ( head , tail ) { return tail ; } export function tail < T > ( list ) { return list . match ( function ( ) { return of < T > ( ) ; } , returnTail ) ; } function prependToAll < T > ( seperator , list ) { return list . match ( function ( ) { return list ; } , function ( head , tail ) { return cons ( seperator , cons ( head , prependToAll ( seperator , tail ) ) ) ; } ) ; } export function intersperse < T > ( seperator , list ) { return list . match ( function ( ) { return list ; } , function ( head , tail ) { return cons ( head , prependToAll ( seperator , tail ) ) ; } ) ; } export function append < T > ( list1 , list2 ) { if ( isEmpty ( list2 ) ) { return list1 ; } else if ( isEmpty ( list1 ) ) { return list2 ; } else { return foldr ( function ( soFar , thisVal ) { return cons ( thisVal , soFar ) ; } , list2 , list1 ) ; } } export function filter < T > ( f , list ) { return foldr ( function ( soFar , val ) { if ( f ( val ) ) { return cons ( val , soFar ) ; } else { return soFar ; } } , of < T > ( ) , list ) ; } export function map < T , U > ( f , list ) { return list . match ( function ( ) { return of < U > ( ) ; } , function ( val , next ) { return new List < U > ( ListType . cons , f ( val ) , map ( f , next ) ) ; } ) ; } export function foldl < T , U > ( f , initialValue , list ) { return list . match ( function ( ) { return initialValue ; } , function ( val , next ) { return foldl ( f , f ( initialValue , val ) , next ) ; } ) ; } export function foldr < T , U > ( f , initialValue , list ) { return list . match ( function ( ) { return initialValue ; } , function ( val , next ) { return f ( foldr ( f , initialValue , next ) , val ) ; } ) ; } export function reverse < T > ( listToReverse ) { return foldl ( function ( soFar , val ) : List < T > { return cons ( val , soFar ) ; } , of < T > ( ) , listToReverse ) ; } export function fromArray < T > ( array ) { return array . reduceRight ( function ( existing , thisOne ) { return cons ( thisOne , existing ) ; } , of < T > ( ) ) ; } export function toArray < T > ( list ) { return foldl ( function ( soFar , thisOne ) { soFar . push ( thisOne ) ; return soFar ; } , [ ] , list ) ; }