С каждого по варианту! Выриант Трурля красив, но я бы предпочел что-нибудь прямолинейное, типа этого
xlist = seqFrom 1
where seqFrom x = x : (seqFrom $! if x>0 then -x-2 else -x+2)
Оператор вызова по значению $! устраняет ненужную ленивость — исключает возможность образования последовательности нуль-арных "функций", ссылающихся друг на друга, и тем самым не позволяющих освободить занимаемую ими память.
Решил немного разобратся с классами. Ввёл класс Reflection. К переменным с типом, относящимся к данному классу (или как правильно сказать ?) можно применить ф-ию typeof, возвращающую строковое представление типа.
class Reflection a where
typeof :: a -> String
instance Reflection Char where
typeof _ = "Char"
instance Reflection Bool where
typeof _ = "Bool"
instance Reflection Integer where
typeof _ = "Integer"
instance Reflection Int where
typeof _ = "Int"
data Point a = Pt2D a a|Pt3D a a a
instance Reflection (Point a) where
typeof (Pt2D _ _) = "Point2D"
typeof (Pt3D _ _ _) = "Point3D"
typeofInt :: Int -> String
typeofInt x = typeof x
typeofInteger :: Integer -> String
typeofInteger x = typeof x
Почему-то typeofInt и typeofInteger работают и выводят что нужно, а вот если ввести typeof 22 (среда — Husg for Windows 32), то:
ERROR — Unresolved overloading
*** Type : (Num a, Reflection a) => [Char]
*** Expression : typeof 22
Здравствуйте, Sergey J. A., Вы писали:
SJA>Почему-то typeofInt и typeofInteger работают и выводят что нужно, а вот если ввести typeof 22 (среда — Husg for Windows 32), то:
SJA>ERROR — Unresolved overloading
SJA>*** Type : (Num a, Reflection a) => [Char]
SJA>*** Expression : typeof 22
SJA>В чём засада ?
Потому что числовой литерал 22 сам по себе не имеет типа; это как бы полиморфная функция без параметров.
Prelude> :t 22
22 :: Num a => a
Возникает неоднозначность, поскольку из typeof 22 вытекает лишь ограничение Reflection a.
Аналогично:
module Test
where
f :: (Num a) => () -> a
f = f -- вычислять эту функцию нельзя, но тип она имеет :)
g = f ()
------------
--- Hugs ---
Test> :t g
g :: Num a => a
Test> :t (g + 1/2)
g + 1 / 2 :: Fractional a => a -- Fractional является подклассом Num, поэтому произвели уточнение
Test> :t (g>>g)
g >> g :: (Monad a, Num (a b)) => a b -- конъюнкция ограничений
Вот если ты напишешь модуль, где будут определены глобальные константы
module Test
where
x = 22 -- тип x зависит от defaults текущего модуля, и обычно равен Integer
y = 22::Int -- явное указание типа
------------
--- Hugs ---
Test> :t x
x :: Integer
Test> :t y
y :: Int
Здравствуйте, Кодт, Вы писали:
К>Потому что числовой литерал 22 сам по себе не имеет типа; это как бы полиморфная функция без параметров. К>
К>Prelude> :t 22
К>22 :: Num a => a
К>
К>Возникает неоднозначность, поскольку из typeof 22 вытекает лишь ограничение Reflection a.
Тут вроде немного понял... Т.е. выражение typeof 22 не вычисляется до конца, т.к. интерпретатор не может выбрать какой тип подставить вместо a и завершить вычисление:
(Reflection a, Num a) => [Char]
Аналогично 22:
Num a => a
это выражение не "вычислится" пока мы не уточним тип. Например: 22::Int, либо интерпретатору не станет ясно, какой тип от 'ф-ии' 22 ожидается.
Но что тогда в этом выражении означает :: ? Я не нашёл ничего в документации кроме использования :: в объявлениях типов. Тем более, что следующий код не работает:
(typeof 22)::Int
Хотя, только что заметил, что, если бы тип выражения был
(Reflection a, Num a) => a
То (typeof 22)::Int срабатывает как и ожидалось
В дальнейшем коде я пока не смог разобратся, однако есть некоторое несоответствие: К>Аналогично: К>
К>module Test
К>where
К>f :: (Num a) => () -> a
К>f = f -- вычислять эту функцию нельзя, но тип она имеет :)
К>g = f ()
К>------------
К>--- Hugs ---
Test>> :t g
К>g :: Num a => a
К>
Здравствуйте, Sergey J. A., Вы писали:
SJA>Здравствуйте, Кодт, Вы писали:
SJA>Всё, я догнал, что происходит в Вашем примере. Вот только не понял, зачем так запутано ? Вроде должно хватить:
Да... это на меня нашло помутнение. Конечно же, достаточно было f:(Num a)=>a
По поводу :: в выражениях. Этот оператор конкретизирует тип полиморфного выражения и используется
— когда нужно устранить неоднозначность,
— для уточнения типа результата,
— для направления вывода типов в нужное русло.
module Test
where
ex x y z = (x+y, z+1) -- (Num a, Num b) => a->a->b -> (a,b) Это полиморфная функция
ex' = ex -- Integer->Integer->Integer -> (Integer,Integer) Константа, по умолчанию тип конкретизирован
ex'' :: (Num a) => a->a->a -> (a,a)
ex'' = ex -- (Num a) => a->a->a -> (a,a) Принудительно сделали полиморфную константу
ex1 y z = ex 10 y z -- (Num a, Num b) => a->b -> (a,b)
ex1' = ex 10 -- Integer->Integer -> (Integer,Integer)
ex1'' = ex'' 10 -- Integer->Integer -> (Integer,Integer)
ex2 y z = ex (10::Int) y z -- (Num b) => Int->b -> (Int,b) Полиморфная функция, тип одного аргумента (и результата) конкретный
ex2' = ex (10::Int) -- Int->Integer -> (Int,Integer) Константа, обратите внимание на тип
ex2'' = ex'' (10::Int) -- Int->Int -> (Int,Int)
A>немного читал документацию по Haskell...
A>но что такое xlist'? всмысле ' после имени функции
Ну, я прочитал, что ' можно использовать в имени. И обычно используется для именования "дополнительных" ф-ий. Так что вместо xlist' можно было бы взять и любое другое имя, например xlistImpl