gchi> :cd c:/some/haskell
ghci> :l file.hs
[1 of 1] Compiling Main ( file.hs, interpreted )
Ok, modules loaded: Main.
ghci>
Surely there is a convenient IDE that automatically makes a reload with changes, but I use just an editor with backlight.data Color = Red | Green | Blue
import Data . Word ( Word8 ) -- Word8 Data.Word
data Color = Red | Green | Blue | Custom Word8 Word8 Word8
data List a = Null | Cons a ( List a )
Those. the list of elements a is either empty or consists of (head) a and (tail) List adata List a = Null | Cons { listHead :: a , listTail :: List a }
that automatically detects two functionslistHead :: List a -> a
listTail :: List a -> List a
which are elementary implementedlength Null = 0
length ( Cons _ xs ) = 1 + length xs
Here I used pattern matching. The function parameter is sequentially (the order of determination is important) compared with the samples ( Null
and Cons _ xs
) and the appropriate option is selected. _
means any value, but we do not care. Those. Cons _ xs
passes for any non-empty list.someFunc ( Cons 5 ( Cons _ ( Cons 3 ( Cons _ Null ) ) ) ) = True
someFunc _ = False
But it can only use constructors (and embedded literals). Those. in this example:x = 4
wrong x = True
wrong _ = False
The first option will always work, since x is a free name, and not the value that is defined as 4.someFunc v @ ( Cons 5 ( Cons _ ( Cons 3 ( Cons _ Null ) ) ) ) = -- v - ,
Pattern matching can also be used inside a function. Here is the most general case (sorry for the senselessness of the example, but I don’t remember when such a general case would come to hand with real examples, and the syntax should be shown):someFunc2 n = case n of
Null -> "Null"
Cons _ Null -> "One"
Cons _ ( Cons x _ )
| x == 0 -> "0"
| x == 1 -> "1"
| otherwise -> "otherwise" -- otherwise True
The last three lines in the example above are the so-called pattern guards. When the value falls under the last sample (in this case, in general, it does not have to be the last one and pattern guards can be written for each sample), then the one that is chosen is True
which is selected. The same mechanism works for functions:someFunc3 ( x : xs )
| isSomePredicate x = xs
| x == 0 = []
| otherwise = ( x : xs )
In addition, there is an additional non-standard feature. Instead of writing an expression of the Bool
type, you can write a certain pattern and check any expression for coincidence with it, for example:someFunc4 ( x : xs )
| ( 2 : ys ) <- filter even xs = ys -- 2
| ( 4 : y : [] ) <- xs = [ y ] -- xs 2- , - 4
| otherwise = ( x : xs )
ghci> listHead Null
*** Exception: No match in record selector Main.listHead
ghci> head []
*** Exception: Prelude.head: empty list
The second option gives more information, because in fact the head for an empty list is defined, but it throws an exception. For such cases, you can use the standard error functionlistHead Null = error "listHead: empty list"
listHead ( Cons x _ ) = x
ghci> listHead Null
*** Exception: listHead: empty list
listMap f Null = Null
listMap f ( Cons x xs ) = Cons ( fx ) ( listMap f xs )
listFilter p Null = Null
listFilter p ( Cons x xs )
| px = Cons x ( listFilter p xs )
| otherwise = listFilter p xs
listFoldr fv Null = v
listFoldr fv ( Cons x xs ) = fx $ listFoldr fv xs
( $ )
Is an application operator, it takes a function and an argument. Its essence is that it eliminates the need to put extra brackets, i.e. insteadfoo ( bar 3 ( baz 56 "x" ) )
foo $ bar 3 $ baz 56 "x"
Null @++ right = right
( @++ ) left Null = left
( Cons l ls ) @++ right = Cons l ( ls @++ right )
Additionally, you can assign priority and left or right associativity to the operator. using the keywords infixl
and infixr
respectively.ghci> :i (++)
(++) :: [a] -> [a] -> [a] -- Defined in GHC.Base
infixr 5 ++
5 is a priority from 1 to 9, the higher it is, the higher the priority( ++ )
, we will set the same priority to it.infixr 5 @++
Recall that a function can be called infixed, for this its name is surrounded by quotes. In fact, it is also possible to determine it, i.e. The following is a completely legal definition of a function:lst `atIndex` n = lst !! n
toList Null = []
toList ( Cons x xs ) = x : ( toList xs )
fromList [] = Null
fromList ( x : xs ) = Cons x ( fromList xs )
[ 1 , 2 , 3 ]
makes [ 1 , 5 , 2 , 5 , 3 ]
(if the inserted element is 5) (for some reason <font> 0 </ font> turns into emptiness, here: ( 0 ) 5 change :)) :listIntersperse with Null = Null
listIntersperse with ( Cons x xs ) = Cons x $ listFoldr ( \ x -> Cons with . Cons x ) Null xs
\ arg1 arg2 argN -> expr
. It can also use pattern matching, but with only one, i.e. it is not possible to write several options for several samples, but if necessary, you can always use case ... of
.\ x -> Cons with . Cons x
\ x -> Cons with . Cons x
, it takes a certain value, and returns a function that attaches the element itself to the list, and then the with
element, as a result we get the list Cons with ( Cons x ... )
with
.listShow lst = "[" ++ ( listFoldr ( ++ ) "" $ listIntersperse "," $ listMap show lst ) ++ "]"
listMap show lst
listInterpserse ","
listFoldr ( ++ ) ""
ghci> show [ 1 , 2 , 3 ] == listShow ( fromList [ 1 , 2 , 3 ] )
True
Source: https://habr.com/ru/post/50600/
All Articles